最大流的一种类型的题,把每一行,每一列做一个点,连接源点到行,列到汇点,行到列。跑一遍最大流。
如何判断unique? 按行dp, dp[i][j] 表示在当前行,i未满且j不空,(若存在某两行的 dp[i][j]&&dp[j][i] == 1 , 那么结果不唯一 !!!)。
另一种方法:在残留网络中找环,若存在,则答案不唯一。
看代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#include<cstdlib>
#include<queue>
using namespace std;
const int nMax = 1e3+10;
const int INF = 99999999;
struct Edge{
int v,flow,nxt;
}edge[nMax*nMax];
int g[nMax],nume;
int src,sink;
int n,m,k;
int Map[nMax][nMax];
inline int addedge(int u,int v,int flow)
{
edge[++nume].v = v,edge[nume].flow = flow,edge[nume].nxt = g[u],g[u] = nume;
edge[++nume].v = u,edge[nume].flow = 0 ,edge[nume].nxt = g[v],g[v] = nume;
return nume;
}
void init()
{
memset(g,0,sizeof(g));
nume = 1;
}
int tot_x,tot_y;
void build()
{
init();
tot_x = tot_y = 0;
src = 0,sink = n+m+1;
for(int i = 1;i <= n;i++){
int x;
scanf("%d",&x);
tot_x += x;
addedge(src,i,x);
}
for(int i = 1;i <= m;i++){
int x;
scanf("%d",&x);
tot_y += x;
addedge(i+n,sink,x);
}
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++){
Map[i][j] = addedge(i,j+n,k);
}
}
int que[nMax],dist[nMax];
bool dinic_bfs()
{
memset(dist,63,sizeof(dist));
int hc=dist[0];
dist[src] = 0;
que[0] = src;
for(int l = 0,r = 0;l <= r;l++){
int cur = que[l];
for(int i = g[cur]; i ;i = edge[i].nxt){
int v = edge[i].v;
if( edge[i].flow && dist[v]==hc ){
dist[v] = dist[cur] + 1;
if( v == sink )
return true;
que[++r] = v;
}
}
}
return false;
}
int c[nMax],p[nMax],st[nMax];
int dinic_dfs()
{
int ret = 0,top = 0;
memcpy(c,g,sizeof(g));
st[++top] = src;
while( top ){
int cur = st[top];
if( cur != sink ){
int i;
for(i = c[cur]; i ;i = edge[i].nxt)
if( edge[i].flow && dist[edge[i].v] == dist[cur] + 1 )
break;
if( i )
st[++top] = edge[i].v,c[cur] = p[top] = i;
else
--top,dist[cur] = INF;
}
else{
int delta = INF;
for(int i = top;i >= 2;i--)
delta = min(delta,edge[p[i]].flow);
for(int i = top;i >= 2;i--){
edge[p[i]].flow -= delta;
edge[p[i]^1].flow += delta;
if( !edge[p[i]].flow )
top = i-1;
}
ret += delta;
}
}
return ret;
}
int dinic()
{
int ret = 0;
while( dinic_bfs() ){
ret += dinic_dfs();
}
return ret;
}
int dp[nMax][nMax];
int is()
{
memset(dp,0,sizeof(dp));
int v1,v2;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
for(int kk=j+1;kk<=m;kk++){
v1=v2=0;
if(edge[Map[i][j]].flow<k && edge[Map[i][kk]].flow>0)
if(dp[kk][j]==1) {return 1;}
else v1=1;
if(edge[Map[i][kk]].flow<k && edge[Map[i][j]].flow>0)
if(dp[j][kk]==1) {return 1;}
else v2=1;
if(v1) dp[j][kk]=1;
if(v2) dp[kk][j]=1;
}
}
return 0;
}
int vis[nMax];
int main()
{
while( scanf("%d %d %d",&n,&m,&k) != EOF ){
build();
int temp = dinic();
int flag = 0;
if( tot_x != tot_y || tot_x != temp )
puts("Impossible");
else if( flag=is() )
puts("Not Unique");
else{
puts("Unique");
for(int i = 1;i <= n;i++){
for(int j = 1;j < m;j++)
printf("%d ",edge[Map[i][j]].flow);
printf("%d\n",edge[Map[i][m]].flow);
}
}
}
return 0;
}
方法二:
bool dfs(int cur,int fa,int _final)
{
vis[cur] = 1;
for(int i = g[cur]; i ;i = edge[i].nxt){
int v = edge[i].v;
if( v == fa )
continue;
if( v == _final && edge[i].flow )
return true;
else if( !vis[v] && edge[i].flow ){
if( dfs(v,cur,_final) )
return true;
}
}
return false;
}