题目是最大流问题,只是需要判断最大流的多解,可以通过判断最大流中是否存在环。
#include<vector>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<queue>
using namespace std;
#define INF 1e9
#define maxn 1000
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define mset(x) memset(x,0,sizeof(x))
struct Edge{
int from, to, cap, flow;
Edge(int from, int to, int cap, int flow):from(from), to(to), cap(cap), flow(flow){}
};
struct Dicnic{
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn], cur[maxn];
void init(int n){
this->n = n;
mset(cur);
mset(d);
rep(i,0,n) G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap){
edges.push_back( Edge(from, to, cap, 0) );
edges.push_back( Edge(to, from, 0, 0) );
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BFS() {
mset(vis);
queue<int> Q;
Q.push(s);
d[s]=0;
vis[s]=1;
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 s, int t){
this->s = s;
this->t = t;
int flow = 0;
while(BFS()){
mset(cur);
flow += DFS(s,INF);
}
return flow;
}
bool isloop[maxn];
bool judge(int u, int fa){//以一个点为起点,判断是否有环
if(isloop[u])
return true;
isloop[u]=1;
for(int i=0;i<G[u].size();i++)
{
if(G[u][i] == (fa^1)) //不能从过来的边回去
continue;
if(edges[G[u][i]].to == t || edges[G[u][i]].to == s) //不能跑到源点和起点
continue;
if(edges[G[u][i]].cap-edges[G[u][i]].flow > 0)
if( judge(edges[G[u][i]].to, G[u][i]) )
return true;
}
isloop[u]=0;
return false;
}
bool haveloop(int x){
//判断整个图是否有环,枚举左边的每个点(行节点)作为起点,
mset(isloop);
rep(i,1,x){
if(judge(i,-1))
return true;
}
return false;
}
int mat[410][410];
void getAns(int x){ //输出唯一解
mset(mat);
for(int i=0;i<edges.size();i++){
if(edges[i].cap && edges[i].from>0 && edges[i].from<=x){
mat[edges[i].from][edges[i].to-x] = edges[i].flow;
}
}
}
};
Dicnic solve;
int n, m, k, row[410], col[410];
int main(){
// freopen("a.txt","r",stdin);
// freopen(".out","w",stdout);
while(cin>>n>>m>>k){
int flag=1,sumR=0,sumC=0;//Impossible是0,unique是1,not unique是2
solve.init(n+m+2);
rep(i,1,n){
cin>>row[i];
solve.AddEdge(0,i,row[i]);
if(row[i]>m*k) flag=0;
sumR += row[i];
}
rep(i,1,m){
cin>>col[i];
solve.AddEdge(n+i,n+m+1,col[i]);
if(col[i]>n*k) flag=0;
sumC += col[i];
}
if(sumR != sumC) flag=0;
if(flag==0){ puts("Impossible"); continue; }
rep(i,1,n)
rep(j,1,m){
solve.AddEdge(i,n+j,k);
}
int res=solve.MaxFlow(0,n+m+1);
if(res != sumC)//满流
puts("Impossible");
else{
if(solve.haveloop(n))
puts("Not Unique");
else{
puts("Unique");
solve.getAns(n);
rep(i,1,n){
for(int j=1;j<m;j++)
printf("%d ",solve.mat[i][j]);
printf("%d\n",solve.mat[i][m]);
}
}
}
}
return 0;
}
/*
DESCRIPTION:
n*m的格子,给出每行的元素和,每列的元素和
每个格子的最大值为k
询问是否有解
如果row[i]>m*k || col[i]>n*k 则无解
*/