网络流hdu4888(多校联合)


Redraw Beautiful Drawings

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


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
 

题意:

n*m的格子里面有数字0~K  现给出每一行和每一列的和  求格子里的值(唯一解时输出值  可能多解或无解)


思路:

首先要想到这题可以用网络流搞  不管从数据范围入手还是真的有思路

接着建图  (1)S->行 容量sum行  (2)列->T 容量sum列  (3)行->列 容量K  跑最大流如果满流则至少一个解

理解一下这个流就是说从行x进去的流量  经过(x,y)格子传递后  从列y出去  那么这时如果满流不就是满足题意么

接下来判断是否唯一解  可以想到  假设解不唯一  则有以下结论

从某个点开始  在这个点+g  在与它同行的某个点-g  再在新点的同列的某个点+g  一直不断延续这条路 类似这样:

+g     -g

-g      +g

形成一个新的解  像不像从某个点搬运了一点东西??  然后搬一圈!!  就是这个圈所以解不唯一!!

那么我们在残余网络中dfs  如果找到一个长度>2的圈  那么必然有其他解(按着这个圈搬一搬!)

dfs最暴力即可  这是队友说的  基本都是4个点就围成圈了  点数不可能太多


#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=810;
const int INF=1000000000;
int sumx[maxn],sumy[maxn];
int n,m,k,nn,st,en;
int vis[maxn],pre[maxn],cnt;
int dis[maxn],gap[maxn],cur[maxn],head[maxn];

struct node
{
    int v,f,next;
}edge[maxn*maxn*2];
void add_edge(int x,int y,int f)
{
    edge[cnt].v=y;
    edge[cnt].f=f;
    edge[cnt].next=head[x];
    head[x]=cnt++;
    edge[cnt].v=x;
    edge[cnt].f=0;
    edge[cnt].next=head[y];
    head[y]=cnt++;
}
int SAP(int st,int en)
{
    for(int i=0;i<=nn;i++)
    {
        cur[i]=head[i];
        dis[i]=gap[i]=0;
    }
    int u=0;
    int flow=0,aug=INF;
    gap[st]=nn;
    u=pre[st]=st;
    bool flag;
    while(dis[st]<nn)
    {
        flag=0;
        for(int &j=cur[u];j!=-1;j=edge[j].next)
        {
            int v=edge[j].v;
            if(edge[j].f>0&&dis[u]==dis[v]+1)
            {
                flag=1;
                if(edge[j].f<aug)aug=edge[j].f;
                pre[v]=u;
                u=v;
                if(u==en)
                {
                    flow+=aug;
                    while(u!=st)
                    {
                        u=pre[u];
                        edge[cur[u]].f-=aug;
                        edge[cur[u]^1].f+=aug;
                    }
                    aug=INF;
                }
                break;
            }
        }

        if(flag)continue;
        int mindis=nn;
        for(int j=head[u];j!=-1;j=edge[j].next)
        {
            int v=edge[j].v;
            if(dis[v]<mindis&&edge[j].f>0)
            {
                mindis=dis[v];
                cur[u]=j;
            }
        }
        if((--gap[dis[u]])==0)break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];

    }
    return flow;
}
bool dfs(int u,int fa)
{
    vis[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(!edge[i].f||v==fa)continue;
        if(vis[v]||dfs(v,u))return true;
    }

    vis[u]=0;
    return false;
}
bool findcircle(int fn)
{
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=fn;i++)
    {
        if(!vis[i])
        {
            vis[i]=1;
            if(dfs(i,i))
                return true;
            vis[i]=0;
        }
    }
    return false;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
        memset(sumx,0,sizeof(sumx));
        memset(sumy,0,sizeof(sumy));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&sumx[i]);
            sumx[0]+=sumx[i];
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&sumy[i]);
            sumy[0]+=sumy[i];
        }
        if(sumx[0]!=sumy[0])
        {
            printf("Impossible\n");
            continue;
        }
        cnt=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            add_edge(i,n+j,k);
        int num=cnt;
        for(int i=1;i<=n;i++)
            add_edge(0,i,sumx[i]);
        for(int j=1;j<=m;j++)
            add_edge(n+j,n+m+1,sumy[j]);
        nn=n+m+2;
        st=0,en=n+m+1;//cout<<1;
        int ans=SAP(st,en);//cout<<2;
        if(ans!=sumx[0])
        {
            printf("Impossible\n");
            continue;
        }
        if(findcircle(n))
        {
            printf("Not Unique\n");
            continue;
        }
        printf("Unique\n");
        for(int i=0;i<num;i+=2)
        {
            printf("%d", k - edge[i].f);
            if (edge[i].v==n+m)
                putchar('\n');
            else
                putchar(' ');
        }
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值