hdu4975 網路流及‘刪邊法’判是否為唯一流

life4711發表於2015-08-05

http://acm.hdu.edu.cn/showproblem.php?pid=4975



Problem Description
Dragon is studying math. One day, he drew a table with several rows and columns, randomly wrote numbers on each elements of the table. Then he counted the sum of each row and column. Since he thought the map will be useless after he got the sums, he destroyed the table after that.

However Dragon's mom came back and found what he had done. She would give dragon a feast if Dragon could reconstruct the table, otherwise keep Dragon hungry. Dragon is so young and so simple so that the original numbers in the table are one-digit number (e.g. 0-9).

Could you help Dragon to do that?
 

Input
The first line of input contains only one integer, T(<=30), the number of test cases. Following T blocks, each block describes one test case.

There are three lines for each block. The first line contains two integers N(<=500) and M(<=500), showing the number of rows and columns.

The second line contains N integer show the sum of each row.

The third line contains M integer show the sum of each column.
 

Output
Each output should occupy one line. Each line should start with "Case #i: ", with i implying the case number. For each case, if we cannot get the original table, just output: "So naive!", else if we can reconstruct the table by more than one ways, you should output one line contains only: "So young!", otherwise (only one way to reconstruct the table) you should output: "So simple!".
 

Sample Input
3 1 1 5 5 2 2 0 10 0 10 2 2 2 2 2 2
 

Sample Output
Case #1: So simple! Case #2: So naive! Case #3: So young!
/**
hdu 4975 網路流及‘刪邊法’判是否為唯一流
題目大意:給定一個n*m的棋盤,給出每行的和以及每列的和,問是否可以確定出該棋盤(唯一,多解or無解)
解題思路:源點與各行建邊,流量行和,匯點與各列建邊,流量列和,行和列相互建邊,流量9。跑網路流,滿流有解;
          至於判斷多解,我們對殘餘網路進行dfs判斷是否能找出邊數大於2的非零環,若殘餘網路上有多個點構成一
          個環,那麼流量可在這個環上調整,某條邊上多餘的流量可以被環上的其他的邊彌補回來。所以如果殘餘網
          絡上存在一個邊數大於2的環,那麼問題則是多解。
*/
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int oo=1e9;
const int mn=1015;
const int mm=505*505*3;
///=========最大流=========
int node,src,dest;
int ver[mm],flow[mm],nex[mm];
int head[mn],ip,work[mn],dis[mn],q[mn];
void prepare(int _node,int _src,int _dest)
{
    node=_node,src=_src,dest=_dest;
    memset(head,-1,sizeof(head));
    ip=0;
}

void addedge(int u,int v,int c)
{
    ver[ip]=v,flow[ip]=c,nex[ip]=head[u],head[u]=ip++;
    ver[ip]=u,flow[ip]=0,nex[ip]=head[v],head[v]=ip++;
}

bool Dinic_bfs()
{
    int i,u,v,l,r=0;
    for(i=0; i<node; i++)dis[i]=-1;
    dis[q[r++]=src]=0;
    for(l=0; l<r; l++)
    {
        for(i=head[u=q[l]]; i!=-1; i=nex[i])
        {
            if(flow[i]&&dis[v=ver[i]]<0)
            {
                dis[q[r++]=v]=dis[u]+1;
                if(v==dest)return 1;
            }
        }
    }
    return 0;
}

int Dinic_dfs(int u,int exp)
{
    if(u==dest)return exp;
    for(int &i=work[u],v,tmp; i>=0; i=nex[i])
    {
        if(flow[i]&&dis[v=ver[i]]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,flow[i])))>0)
        {
            flow[i]-=tmp;
            flow[i^1]+=tmp;
            return tmp;
        }
    }
    return 0;
}
int Dinic_flow()
{
    int i,ret=0,delta;
    while(Dinic_bfs())
    {
        for(i=0; i<node; i++)work[i]=head[i];
        while(delta=Dinic_dfs(src,oo))ret+=delta;
    }
    return ret;
}
///============判環=============
int walked[mn];
bool dfs(int u,int pre)
{
    int biu=-1;
    walked[u]=true;
    for(int i=head[u]; i!=-1; i=nex[i])
    {
        int v=ver[i];
        if(v==pre)continue;
        if(flow[i]>0)
        {
            if(walked[v])return true;
            if(dfs(v,u))return true;
        }
        if(biu==-1)head[u]=nex[i];
        else nex[biu]=nex[i];
        biu=i;
    }
    walked[u]=false;
    return false;
}

bool judge()
{
    memset(walked,false,sizeof(walked));
    for(int i=1; i<=node; i++)
    {
        if(dfs(i,-1))return true;
    }
    return false;
}
///==============================

int n,m,c1[mn],c2[mn];
int main()
{
    int T,tt=0;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        int sum1=0,sum2=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&c1[i]);
            sum1+=c1[i];
        }
        for(int i=1; i<=m; i++)walked[mn];
        {
            scanf("%d",&c2[i]);
            sum2+=c2[i];
        }
        printf("Case #%d: ",++tt);
        if(sum1!=sum2)
        {
            puts("So naive!");
            continue;
        }
        ///====建邊====
        prepare(n+m+2,0,n+m+1);
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                addedge(i,j+n,9);
            }
        }
        for(int i=1; i<=n; i++)
        {
            addedge(src,i,c1[i]);
        }
        for(int i=1; i<=m; i++)
        {
            addedge(i+n,dest,c2[i]);
        }
        ///============
        if(Dinic_flow()!=sum1)
        {
            puts("So naive!");
        }
        else
        {
            if(judge())
                puts("So young!");
            else
                puts("So simple!");
        }
    }
    return 0;
}

相關文章