现在已知一个矩阵每行每列的和,以及每个元素最大是多少,所有元素都是非负整数,问能否求出矩阵中的元素的值?是无解,多组解,还是唯一解?如果是唯一解,输出他。
网络流,用1~n点表示行,n+1~n+m表示列,源到行的流量为该行元素和,列到汇的流量为该列元素和,每行到每列的流量为该格元素的最大值。
求最大流,如果最大流等于行和等于列和,那么就有解,如果能有多种最大流方案,那么就有多组解。
判断是否有多组最大流方案的方法为:如果从某个点出发,只走剩余流量大于零的边,且在走过一条边之后,不立刻走其反向边,能够回到该点,则有多组最大流方案。
dinic版本:
#include <cstdio>
#include <iostream>
using namespace std;
const int MAXINT=1<<30;
const int N=900;
const int M=170000;
struct Node {
int fe,h,cur,v;
bool vis;
};
struct Edge {
int t,ne,f;
bool vis;
};
Node a[N];
Edge b[M*2];
int d[M];
int s,t,n,p;
void clear(int nn,int ss,int tt) {
n=nn;s=ss;t=tt;
for (int i=1;i<=n;i++) {
a[i].fe=-1;
a[i].v=0;
a[i].vis=false;
}
p=0;
}
int putedge(int x,int y,int f) {
b[p].t=y;
b[p].f=f;
b[p].ne=a[x].fe;
b[p].vis=false;
a[x].fe=p;
p++;
b[p].t=x;
b[p].f=0;
b[p].ne=a[y].fe;
b[p].vis=false;
a[y].fe=p;
p++;
return p-1;
}
bool bfs() {
int i,p,q,j;
for (i=1;i<=n;i++) a[i].h=0;
a[s].h=1;
p=q=0;
d[q++]=s;
while (p<q) {
i=d[p];
for (j=a[i].fe;j!=-1;j=b[j].ne) {
if (a[b[j].t].h==0&&b[j].f>0) {
a[b[j].t].h=a[i].h+1;
if (b[j].t==t) return true;
d[q++]=b[j].t;
}
}
p++;
}
return false;
}
int dfs(int i,int v) {
if (i==t) {
a[t].v+=v;
return v;
}
int ans=0;
for (int &j=a[i].cur;j!=-1;j=b[j].ne) {
if (b[j].f>0&&a[b[j].t].h>a[i].h) {
int tmp=dfs(b[j].t,min(b[j].f,v));
v-=tmp;
b[j].f-=tmp;
b[j^1].f+=tmp;
ans+=tmp;
if (v==0) return ans;
}
}
a[i].v+=ans;
return ans;
}
int flow() {
int i;
a[s].v=MAXINT;
while (bfs()) {
for (i=0;i<=n;i++) a[i].cur=a[i].fe;
dfs(s,MAXINT);
}
return a[t].v;
}
int row[410];
int col[410];
int ans[410][410];
int sumrow,sumcol;
bool dfss(int i,int p) {
if (a[i].vis) return true;
a[i].vis=true;
b[p].vis=true;
for (int j=a[i].fe;j!=-1;j=b[j].ne) {
if (b[j].f&&(j^1)!=p&&!b[j].vis)
if (dfss(b[j].t,j)) return true;
}
a[i].vis=false;
return false;
}
bool multiSolve() {
for (int j=0;j<p;j++) {
if (b[j].f&&!b[j].vis) {
a[b[j^1].t].vis=true;
if (dfss(b[j].t,j)) return true;
a[b[j^1].t].vis=false;
}
}
return false;
}
int main() {
int n,m,k,i,j;
while (scanf("%d%d%d",&n,&m,&k)!=EOF) {
//static int cas=0;
//cerr << cas++ << endl;
clear(n+m+2,n+m+1,n+m+2);
sumcol=sumrow=0;
for (i=0;i<n;i++) {
scanf("%d",&row[i]);
putedge(n+m+1,i+1,row[i]);
sumrow+=row[i];
}
for (i=0;i<m;i++) {
scanf("%d",&col[i]);
putedge(i+n+1,n+m+2,col[i]);
sumcol+=col[i];
}
for (i=0;i<n;i++)
for (j=0;j<m;j++)
ans[i][j]=putedge(i+1,j+n+1,k);
int maxf=flow();
//printf("%d %d %d\n",maxf,sumcol,sumrow);
if (maxf==sumcol&&sumcol==sumrow) {
if (multiSolve()) {
printf("Not Unique\n");
} else {
printf("Unique\n");
for (i=0;i<n;i++) {
for (j=0;j<m;j++) {
if (j) printf(" ");
printf("%d",b[ans[i][j]].f);
}
printf("\n");
}
}
} else {
printf("Impossible\n");
}
}
return 0;
}
isap版本:
#include <cstdio>
#include <iostream>
using namespace std;
const int MAXINT=1<<30;
const int N=900;
const int M=170000;
struct Edge {
int t,f;
bool vis;
Edge *ne,*p;
Edge () {}
Edge (int tt,int ff,Edge *nee) {
t=tt;f=ff;ne=nee;vis=false;
}
void *operator new (size_t, void *p) {
return p;
}
};
Edge b[M*2];
Edge *bp,*fe[N],*cur[N];
bool vis[N];
int n,s,t;
int h[N],vh[N];
void clear(int nn,int ss,int tt) {
n=nn;s=ss;t=tt;
for (int i=1;i<=n;i++) {
fe[i]=NULL;
vis[i]=false;
}
bp=b;
}
Edge *putedge(int x,int y,int f) {
fe[x]=new(bp++)Edge(y,f,fe[x]);
fe[y]=new(bp++)Edge(x,0,fe[y]);
fe[x]->p=fe[y];
fe[y]->p=fe[x];
return fe[y];
}
int aug(int i,int f) {
if (i==t) return f;
int minh=n;
Edge *seg=cur[i],*&j=cur[i];
do {
if (j->f) {
if (h[j->t]+1==h[i]) {
int tmp=aug(j->t,min(j->f,f));
if (tmp) {
j->f-=tmp;
j->p->f+=tmp;
return tmp;
}
}
minh=min(minh,h[j->t]+1);
if (h[s]==n) return 0;
}
j=j->ne;
if (j==NULL) j=fe[i];
} while (j!=seg);
if (!--vh[h[i]]) h[s]=n;
else ++vh[h[i]=minh];
return 0;
}
int flow() {
int ans=0;
vh[0]=n;
for (int i=1;i<=n;i++) {
cur[i]=fe[i];
h[i]=vh[i]=0;
}
while (h[s]<n) ans+=aug(s,MAXINT);
return ans;
}
int row[410];
int col[410];
Edge *ans[410][410];
int ans2[410][410];
int sumrow,sumcol;
bool dfs(int i,Edge *p) {
if (vis[i]) return true;
vis[i]=true;
p->vis=true;
for (Edge *j=fe[i];j;j=j->ne) {
if (j->f&&j->p!=p&&!j->vis)
if (dfs(j->t,j)) return true;
}
vis[i]=false;
return false;
}
bool multiSolve() {
for (Edge *j=b;j!=bp;j++) {
if (j->f&&!j->vis) {
vis[j->p->t]=true;
if (dfs(j->t,j)) return true;
vis[j->p->t]=false;
}
}
return false;
}
int main() {
int n,m,k,i,j;
while (scanf("%d%d%d",&n,&m,&k)!=EOF) {
clear(n+m+2,n+m+1,n+m+2);
sumcol=sumrow=0;
for (i=0;i<n;i++) {
scanf("%d",&row[i]);
putedge(n+m+1,i+1,row[i]);
sumrow+=row[i];
}
for (i=0;i<m;i++) {
scanf("%d",&col[i]);
putedge(i+n+1,n+m+2,col[i]);
sumcol+=col[i];
}
for (i=0;i<n;i++)
for (j=0;j<m;j++)
ans[i][j]=putedge(i+1,j+n+1,k);
int maxf=flow();
//printf("%d %d %d\n",maxf,sumcol,sumrow);
if (maxf==sumcol&&sumcol==sumrow) {
if (multiSolve()) {
printf("Not Unique\n");
} else {
printf("Unique\n");
for (i=0;i<n;i++) {
for (j=0;j<m;j++) {
if (j) printf(" ");
printf("%d",ans[i][j]->f);
}
printf("\n");
}
}
} else {
printf("Impossible\n");
}
}
return 0;
}