题目是一个矩阵,每行每列的数字的和都有一个上限,问是否存在可行方案,并且可行方案是否唯一。
第一问比较简单,行列建图,s到每个行节点容量为该行上限,每个列节点连接到t,容量为该列的上限,求最大流,如果满流则有可行方案。第二问就是判断最大流是否唯一,就是在原图中找一个环(经过一条边后不能马上走反向边),环上的边cap-flow都大于0。如果有这个环,那么不唯一,否则唯一。因为流量为k的两个流量图的差别肯定是一个个的环,否则流量不相同,只要按照这个环进行流量的重新分配就可以找到另一个方案。
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> using namespace std; #define maxn 1000 #define INF 10000000 struct Edge { int from, to, cap, flow; }edges[360000]; int n, m, s, t, kk, cnt; vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号 bool vis[maxn]; // BFS使用 int d[maxn]; // 从起点到i的距离 int cur[maxn]; // 当前弧指针 int map[410][410]; void AddEdge(int from, int to, int cap) { edges[cnt].from=from; edges[cnt].to=to; edges[cnt].cap=cap; edges[cnt].flow=0; G[from].push_back(cnt); cnt++; edges[cnt].from=to; edges[cnt].to=from; edges[cnt].cap=0; edges[cnt].flow=0; G[to].push_back(cnt); cnt++; } bool BFS() { memset(vis, 0, sizeof(vis)); queue<int> Q; Q.push(s); vis[s] = 1; d[s] = 0; while(!Q.empty()) { int x = Q.front(); Q.pop(); for(int i = 0; i < G[x].size(); i++) { Edge& e = edges[G[x][i]]; if(!vis[e.to] && e.cap > e.flow) { vis[e.to] = 1; d[e.to] = d[x] + 1; Q.push(e.to); } } } return vis[t]; } int DFS(int x, int a) { if(x == t || a == 0) return a; int flow = 0, f; for(int& i = cur[x]; i < G[x].size(); i++) { Edge& e = edges[G[x][i]]; if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) { e.flow += f; edges[G[x][i]^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Maxflow() { int flow = 0; while(BFS()) { memset(cur, 0, sizeof(cur)); flow += DFS(s, INF); } return flow; } int dfs(int x,int fa) { int i; for(i=0;i<G[x].size();i++) { int v=edges[G[x][i]].to; int cap=edges[G[x][i]].cap; int flow=edges[G[x][i]].flow; if(v==fa) continue; if(v!=s&&v!=t&&cap-flow) { if(vis[v]) return 1; vis[v]=1; if(dfs(v,x)) return 1; vis[v]=0; } } return 0; } int main() { while(scanf("%d%d%d",&n,&m,&kk)!=EOF) { int i,j,x; int flag=0; int sum1=0,sum2=0; s=0;t=n+m+1;cnt=0; for(i=0;i<=t;i++) G[i].clear(); for(i=1;i<=n;i++) {scanf("%d",&x); sum1+=x; AddEdge(s,i,x);} for(i=1;i<=m;i++) {scanf("%d",&x); sum2+=x; AddEdge(i+n,t,x);} if(sum1!=sum2) {printf("Impossible\n"); continue;} for(i=1;i<=n;i++) for(j=1;j<=m;j++) AddEdge(i,j+n,kk); if(Maxflow()!=sum1) {printf("Impossible\n"); continue;} memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++) { vis[i]=1; if(dfs(i,-1)) { flag=1; break; } vis[i]=0; } if(flag==1) printf("Not Unique\n"); else { printf("Unique\n"); for(j=1;j<=n;j++) for(i=0;i<G[j].size();i++) { int v=edges[G[j][i]].to; if(v!=s) map[j][v-n]=edges[G[j][i]].flow; } for(i=1;i<=n;i++) { printf("%d",map[i][1]); for(j=2;j<=m;j++) printf(" %d",map[i][j]); printf("\n"); } } } return 0; }