http://acm.hdu.edu.cn/showproblem.php?pid=4888
添加一个源点与汇点,建图如下:
1. 源点 -> 每一行对应的点,流量限制为该行的和
2. 每一行对应的点 -> 每一列对应的点,流量限制为 K
3. 每一列对应的点 -> 汇点,流量限制为该列的和
求一遍最大流,若最大流与矩阵之和相等,说明有解,否则无解。判断唯一解,是判断残量网络中是否存在一个长度大于2的环,若存在说明有多解,否则有唯一解,解就是每条边行i->列j的流量。
#include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <cstdlib> using namespace std; const int maxn=500,maxm=maxn*maxn; int next[maxm*2],num[maxm*2],r[maxm*2],a[maxn*2],row_sum[maxn],col_sum[maxn],n,m,K,tt,T,d[maxn*2],st[maxn*2],cod[maxn][maxn]; int h[maxn*2],vh[maxn*2]; bool don[maxm*2],in[maxn*2]; void insert(int x,int y,int rr) { next[++tt]=a[x];num[tt]=y;r[tt]=rr;a[x]=tt; next[++tt]=a[y];num[tt]=x;r[tt]=0;a[y]=tt; } void construct() { tt=1;T=n+m+1; for (int i=0;i<=T;i++) a[i]=0; for (int i=1;i<=n;i++) insert(0,i,row_sum[i]); for (int i=1;i<=m;i++) insert(i+n,T,col_sum[i]); for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) { insert(i,j+n,K); cod[i][j]=tt; } } } int dfs(int x,int y) { if (x==T) return y; int sig=st[x],minh=T+1; do { if (r[st[x]]) { if (h[num[st[x]]]+1==h[x]) { int k=dfs(num[st[x]],min(y,r[st[x]])); if (k) { r[st[x]]-=k; r[st[x]^1]+=k; return k; } } minh=min(minh,h[num[st[x]]]+1); if (h[0]>T) return 0; } st[x]=next[st[x]]; if (st[x]==0) st[x]=a[x]; }while (sig!=st[x]); if (vh[h[x]]--==0) h[0]=T+1; vh[h[x]=minh]++; return 0; } int max_flow() { for (int i=0;i<=T;i++) h[i]=vh[i]=0; for (int i=0;i<=T;i++) st[i]=a[i]; vh[0]=T+1; int ret=0; while (h[0]<=T) ret+=dfs(0,K+1); return ret; } /*bool find_circle() { deque <int> q; for (int i=0;i<=T;i++) d[i]=0; for (int i=0;i<=T;i++) { for (int p=a[i];p;p=next[p]) { if (r[p]) d[i]++; } if (d[i]==0) q.push_back(i); } int cnt=T+1; while (!q.empty()) { int x=q.front(); cnt--; q.pop_front(); for (int p=a[x];p;p=next[p]) { if (r[p^1]) { d[num[p]]--; if (d[num[p]]==0) q.push_back(num[p]); } } } return cnt; }*/ bool visit(int x,int ed) { if (don[ed]) return in[x]; don[ed]=true; in[x]=true; for (int p=a[x];p;p=next[p]) { if (r[p] && (ed^p)!=1) if (visit(num[p],p)) return true; } in[x]=false; return false; } bool find_circle() { for (int i=0;i<=T;i++) in[i]=false; for (int i=1;i<=tt;i++) don[i]=false; int col=0; for (int i=2;i<=tt;i++) { if (r[i] && !don[i]) { in[num[i^1]]=true; if (visit(num[i],i)) return true; in[num[i^1]]=false; } } return false; } void print_scheme() { printf("Unique\n"); for (int i=1;i<=n;i++) { printf("%d",r[cod[i][1]]); for (int j=2;j<=m;j++) printf(" %d",r[cod[i][j]]); printf("\n"); } } int main() { while (scanf("%d%d%d",&n,&m,&K)!=EOF) { int tmp=0; for (int i=1;i<=n;i++) { scanf("%d",&row_sum[i]); tmp+=row_sum[i]; } int sum=tmp; for (int i=1;i<=m;i++) { scanf("%d",&col_sum[i]); tmp-=col_sum[i]; } if (tmp) { printf("Impossible\n"); continue; } construct(); if (max_flow()<sum) { printf("Impossible\n"); continue; } if (find_circle()) { printf("Not Unique\n"); }else print_scheme(); } return 0; }