题目地址:
http://acm.hdu.edu.cn/showproblem.php?pid=4888
思路:设置一源点、汇点。将每行看做一点,从源点连边,容量为改行元素和;将每列看做一点,从该点向汇点连边,容量为该列元素和。每行每列连边,容量为k。求最大流,若满流,则存在解。存在解时,若残量网络中存在环,则流量可绕环一圈而不改变最大流,则此时存在多解。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <numeric>
#define debu
using namespace std;
typedef long long LL;
const int maxn=800+50;
const int INF=0x3f3f3f3f;
const int maxm=maxn*maxn;
struct ISAP
{
int head[maxn], cur[maxn], gap[maxn], dis[maxn], pre[maxn];
int to[maxm], next[maxm], flow[maxm];
int n, ecnt, st, ed;
void init(int n)
{
ecnt = 0;
this->n = n;
memset(head,-1,sizeof(head));
}
void addedge(int u, int v, int c)
{
to[ecnt] = v,flow[ecnt] = c,next[ecnt] = head[u],head[u] = ecnt++;
to[ecnt] = u,flow[ecnt] = 0,next[ecnt] = head[v],head[v] = ecnt++;
}
void bfs()
{
memset(dis,0x3f,sizeof(dis));
queue<int> que;
que.push(ed);
dis[ed] = 0;
while(!que.empty())
{
int u = que.front();
que.pop();
gap[dis[u]]++;
for(int p = head[u]; ~p; p = next[p])
{
int v = to[p];
if(flow[p ^ 1] && dis[u] + 1 < dis[v])
{
dis[v] = dis[u] + 1;
que.push(v);
}
}
}
}
int Maxflow(int ss, int tt)
{
st = ss, ed = tt;
int ans = 0, minFlow = INF;
for(int i = 0; i <= n; ++i)
{
cur[i] = head[i];
gap[i] = 0;
}
bfs();
int u = pre[st] = st;
while(dis[st] < n)
{
bool flag = false;
for(int &p = cur[u]; ~p; p = next[p])
{
int v = to[p];
if(flow[p] && dis[u] == dis[v] + 1)
{
flag = true;
minFlow = min(minFlow, flow[p]);
pre[v] = u;
u = v;
if(u == ed)
{
ans += minFlow;
while(u != st)
{
u = pre[u];
flow[cur[u]] -= minFlow;
flow[cur[u] ^ 1] += minFlow;
}
minFlow = INF;
}
break;
}
}
if(flag) continue;
int minDis = n - 1;
for(int p = head[u]; ~p; p = next[p])
{
int &v = to[p];
if(flow[p] && dis[v] < minDis)
{
minDis = dis[v];
cur[u] = p;
}
}
if(--gap[dis[u]] == 0) { break; }
++gap[dis[u] = minDis + 1];
u = pre[u];
}
return ans;
}
}G;
int is_DAG;
int vis[maxn];
int r,c,t,k,tot;
int flag[maxn][maxn];
int check(int u,int fa)
{
if(vis[u]) return 1;
vis[u]=1;
for(int i=G.head[u]; i!=-1; i=G.next[i])
{
int v=G.to[i];
if(v!=fa&&v!=0&&v!=(r+c+1)&&G.flow[i])
if(check(v,u)) return 1;
}
vis[u]=0;
return 0;
}
int main()
{
#ifdef debug
freopen("in.in","r",stdin);
#endif // debug
while(scanf("%d%d%d",&r,&c,&k)!=EOF)
{
is_DAG=1;
G.init(r+c+2);
int sum1=0,sum2=0;
for(int i=1; i<=r; i++)
{
int x;
scanf("%d",&x);
sum1+=x;
G.addedge(0,i,x);
}
for(int i=1; i<=c; i++)
{
int x;
scanf("%d",&x);
sum2+=x;
G.addedge(i+r,r+c+1,x);
}
for(int i=1; i<=r; i++)
for(int j=1; j<=c; j++)
{
G.addedge(i,r+j,k);
flag[i][j]=G.ecnt-2;
}
int maxflow=G.Maxflow(0,r+c+1);
if(sum1!=sum2||maxflow!=sum1) printf("Impossible\n");
else
{
memset(vis,0,sizeof(vis));
for(int i=1; i<=r; i++)
{
if(check(i,-1))
{
is_DAG=0;
break;
}
}
if(!is_DAG) printf("Not Unique\n");
else
{
printf("Unique\n");
for(int i=1; i<=r; i++)
{
for(int j=1; j<c; j++)
printf("%d ",k-G.flow[flag[i][j]]);
printf("%d\n",k-G.flow[flag[i][c]]);
}
}
}
}
return 0;
}