首页 > 代码库 > HDU 4888 Redraw Beautiful Drawings(最大流)

HDU 4888 Redraw Beautiful Drawings(最大流)

题目大意:给你一个n,m,k。n行,m列。然后给你每一行的总和,与每一列的总和,让你在这个n*m的矩阵里面填一个小于等于k的数字,使得满足每一列,每一行的和。如果没有输出“Impossible”,有多解输出“Not Unique”,有唯一的解输出“Unique”,并输出他的解。

从源点到每一行的和建边容量为它的总和,从汇点到列建边容量为它的总和。然后行到列建边容量为数据上限K。然后求是否存在满流,如果从在在判断是否唯一。判唯一的时候,你要看中间是否存在环流,这样的话有些值 你取多少是不会收到影响的。

Redraw Beautiful Drawings

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2238    Accepted Submission(s): 507


Problem Description
Alice and Bob are playing together. Alice is crazy about art and she has visited many museums around the world. She has a good memory and she can remember all drawings she has seen.

Today Alice designs a game using these drawings in her memory. First, she matches K+1 colors appears in the picture to K+1 different integers(from 0 to K). After that, she slices the drawing into grids and there are N rows and M columns. Each grid has an integer on it(from 0 to K) representing the color on the corresponding position in the original drawing. Alice wants to share the wonderful drawings with Bob and she tells Bob the size of the drawing, the number of different colors, and the sum of integers on each row and each column. Bob has to redraw the drawing with Alice‘s information. Unfortunately, somtimes, the information Alice offers is wrong because of Alice‘s poor math. And sometimes, Bob can work out multiple different drawings using the information Alice provides. Bob gets confused and he needs your help. You have to tell Bob if Alice‘s information is right and if her information is right you should also tell Bob whether he can get a unique drawing.
 

Input
The input contains mutiple testcases.

For each testcase, the first line contains three integers N(1 ≤ N ≤ 400) , M(1 ≤ M ≤ 400) and K(1 ≤ K ≤ 40).
N integers are given in the second line representing the sum of N rows.
M integers are given in the third line representing the sum of M columns.

The input is terminated by EOF.
 

Output
For each testcase, if there is no solution for Bob, output "Impossible" in one line(without the quotation mark); if there is only one solution for Bob, output "Unique" in one line(without the quotation mark) and output an N * M matrix in the following N lines representing Bob‘s unique solution; if there are many ways for Bob to redraw the drawing, output "Not Unique" in one line(without the quotation mark).
 

Sample Input
2 2 4 4 2 4 2 4 2 2 2 2 5 0 5 4 1 4 3 9 1 2 3 3
 

Sample Output
Not Unique Impossible Unique 1 2 3 3
 

#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define eps 1e-12
///#define M 1000100
#define LL __int64
///#define LL long long
///#define INF 0x7ffffff
#define INF 0x3f3f3f3f
#define PI 3.1415926535898
#define zero(x) ((fabs(x)<eps)?0:x)

using namespace std;

const int maxn = 1010;

int cnt;
int n, m;
int cur[maxn], head[maxn];
int dis[maxn], gap[maxn];
int aug[maxn], pre[maxn];
int deep[maxn];

struct node
{
    int v, w;
    int next;
} f[500100];
void init()
{
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void add(int u, int v, int w)
{
    f[cnt].v = v;
    f[cnt].w = w;
    f[cnt].next = head[u];
    head[u] = cnt++;

    f[cnt].v = u;
    f[cnt].w = 0;
    f[cnt].next = head[v];
    head[v] = cnt++;
}

int SAP(int s, int e, int n)
{
    int max_flow = 0, v, u = s;
    int id, mindis;
    aug[s] = INF;
    pre[s] = -1;
    memset(dis, 0, sizeof(dis));
    memset(gap, 0, sizeof(gap));
    gap[0] = n;
    for (int i = 0; i <= n; ++i)  cur[i] = head[i];/// 初始化当前弧为第一条弧
    while (dis[s] < n)
    {
        bool flag = false;
        if (u == e)
        {
            max_flow += aug[e];
            for (v = pre[e]; v != -1; v = pre[v]) /// 路径回溯更新残留网络
            {
                id = cur[v];
                f[id].w -= aug[e];
                f[id^1].w += aug[e];
                aug[v] -= aug[e]; /// 修改可增广量,以后会用到
                if (f[id].w == 0) u = v; /// 不回退到源点,仅回退到容量为0的弧的弧尾
            }
        }
        for (id = cur[u]; id != -1; id = f[id].next)/// 从当前弧开始查找允许弧
        {
            v = f[id].v;
            if (f[id].w > 0 && dis[u] == dis[v] + 1) /// 找到允许弧
            {
                flag = true;
                pre[v] = u;
                cur[u] = id;
                aug[v] = min(aug[u], f[id].w);
                u = v;
                break;
            }
        }
        if (flag == false)
        {
            if (--gap[dis[u]] == 0) break; ///gap优化,层次树出现断层则结束算法
            mindis = n;
            cur[u] = head[u];
            for (id = head[u]; id != -1; id = f[id].next)
            {
                v = f[id].v;
                if (f[id].w > 0 && dis[v] < mindis)
                {
                    mindis = dis[v];
                    cur[u] = id; /// 修改标号的同时修改当前弧
                }
            }
            dis[u] = mindis + 1;
            gap[dis[u]]++;
            if (u != s) u = pre[u]; /// 回溯继续寻找允许弧
        }
    }
    return max_flow;
}

int mp[410][410];
int vis[maxn];

bool dfs(int x, int fa)
{
    for(int i = head[x]; i != -1; i = f[i].next)
    {
        if(i == (fa^1)) continue;
        if(!f[i].w) continue;
        if(vis[f[i].v]) return true;
        vis[f[i].v] = 1;
        if(dfs(f[i].v, i)) return true;
        vis[f[i].v] = 0;
    }
    return false;
}

int main()
{
    int k;
    int x, y;
    int S;
    int T;
    int en;
    int sum1;
    int sum2;
    while(~scanf("%d %d %d",&n, &m, &k))
    {
        init();
        sum1 = sum2 = 0;
        S = 0;
        T = n+m+1;
        en = T+1;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&x);
            sum1 += x;
            add(S, i, x);
            for(int j = 1; j <= m; j++) add(i, j+n, k);
        }
        for(int i = 1; i <= m; i++)
        {
            scanf("%d",&y);
            sum2 += y;
            add(i+n, T, y);
        }
        if(sum1 != sum2)
        {
            puts("Impossible");
            continue;
        }
        int ans = SAP(S, T, en);
        if(ans != sum1)
        {
            puts("Impossible");
            continue;
        }
        memset(vis, 0, sizeof(vis));
        int flag = 0;
        for(int i = 1; i <= n; i++)
        {
            if(dfs(i, -1))
            {
                flag = 1;
                break;
            }
        }
        if(flag)
        {
            puts("Not Unique");
            continue;
        }
        memset(mp, 0, sizeof(mp));
        puts("Unique");
        for(int i = 1; i <= n; i++)
        {
            for(int j = head[i]; j != -1; j = f[j].next)
            {
                int x = f[j].v;
                if(x > n && x <= n+m) mp[i][x-n] = k-f[j].w;
            }
        }
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j < m; j++) printf("%d ",mp[i][j]);
            printf("%d\n",mp[i][m]);
        }
    }
    return 0;
}