uva 11082Matrix Decompressing(图论--网络流最大流 Dinic+拆点二分图匹配)
Posted konjac蒟蒻
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uva 11082Matrix Decompressing(图论--网络流最大流 Dinic+拆点二分图匹配)相关的知识,希望对你有一定的参考价值。
题意:有一个N行M列的正整数矩阵,输入N个前1~N行所有元素之和,以及M个前1~M列所有元素之和。要求找一个满足这些条件,并且矩阵中的元素都是1~20之间的正整数的矩阵。输入保证有解,而且1≤N,M≤20。
解法:这题的图转换得极妙!(*^▽^*) 我们可以发现找到的矩阵需要满足3个条件:1.N行M列;2.各行各列的和;3.各元素的大小。再仔细阅读一次题目,发现题目中提到的2个数字相同——“20”,再想想这是不是有什么玄机。
首先可以找到第3个条件的转化,可以用容量来限制,那么这题用网络流可以吗?如果用网络流,那对于元素大小限制就建边为容量19的,因为要求为1~20,而又有流量为0,于是我们就把“流量+1”当成 元素的大小。而第1个条件可以直接转化为 n+m 个点表示各行、列,那么第2个条件也是可以通过与源点和汇点连边处理得到的,也就是我们后面博文会提到的“多源多汇问题”。把源点连边到前 n 个点,边容量就是1~n行的元素之和 再-m,因为前面我们已经把各元素的大小转化为“流量+1”了,那么流量就是“大小-1”,每行有m个元素就是 -m 了。同理,把 n+1~n+m 的元素与汇点相连,边容量是1~M列的元素之和 -N。对于各行各列的和的具体分配就是看这 1~n 与 n+1~n+m 的点之间的边流量了,第 i 行第 j 列的元素大小就是点 i 到点 n+j 的边的反向弧的流量+1.
成功建图之后,就跑一遍Dinic再求出矩阵就好了。?(^∀^●)?
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<queue> 5 #include<iostream> 6 #include<algorithm> 7 using namespace std; 8 9 const int N=25,NN=75,INF=(int)1e9; 10 int st,ed,n,m,len; 11 int last[NN],d[NN],num[N][N]; 12 struct edge{int x,y,next,fl;}a[N*N*2]; 13 queue <int> q; 14 15 int mmin(int x,int y) {return x<y?x:y;} 16 void ins(int x,int y,int fl) 17 { 18 a[++len].x=x,a[len].y=y,a[len].fl=fl; 19 a[len].next=last[x],last[x]=len; 20 a[++len].x=y,a[len].y=x,a[len].fl=0; 21 a[len].next=last[y],last[y]=len; 22 } 23 bool bfs() 24 { 25 while (!q.empty()) q.pop(); 26 memset(d,0,sizeof(d)); 27 q.push(st), d[st]=1; 28 while (!q.empty()) 29 { 30 int x=q.front(); q.pop(); 31 for (int i=last[x];i;i=a[i].next) 32 { 33 int y=a[i].y; 34 if (d[y]||(!a[i].fl)) continue; 35 q.push(y); 36 d[y]=d[x]+1; 37 } 38 } 39 return d[ed]; 40 } 41 int dfs(int x,int flow) 42 { 43 if (x==ed) return flow; 44 int sum=0; 45 for (int i=last[x];i;i=a[i].next) 46 { 47 int y=a[i].y; 48 if (d[y]!=d[x]+1||(!a[i].fl)) continue; 49 int t=dfs(y,mmin(flow-sum, a[i].fl)); 50 sum+=t; 51 a[i].fl-=t,a[i^1].fl+=t; 52 if (sum==flow) break; 53 } 54 if (!sum) d[x]=0; 55 return sum; 56 } 57 void Dinic() 58 { 59 int sum=0; 60 while (bfs()) sum+=dfs(st,INF); 61 /*for (int i=1;i<=n;i++) 62 { 63 int x=i; 64 for (int k=last[x];k;k=a[k].next) 65 { 66 int y=a[k].y; 67 if (!(y>n&&y<=n+m)) continue; 68 mat[x][y]=a[k^1].fl+1; 69 } 70 }*/ 71 } 72 int main() 73 { 74 int T; 75 scanf("%d",&T); 76 for (int kase=1;kase<=T;kase++) 77 { 78 scanf("%d%d",&n,&m); 79 int x,y; st=n+m+1,ed=n+m+2; 80 len=1,y=0; 81 memset(last,0,sizeof(last)); 82 for (int i=1;i<=n;i++) 83 { 84 scanf("%d",&x); 85 ins(st,i,x-y-m);//m 86 y=x; 87 } 88 y=0; 89 for (int i=1;i<=m;i++) 90 { 91 scanf("%d",&x); 92 ins(n+i,ed,x-y-n);//n 93 y=x; 94 } 95 for (int i=1;i<=n;i++) 96 for (int j=1;j<=m;j++) 97 { 98 ins(i,n+j,19); 99 num[i][j]=len; 100 //printf("%d %d %d %d\n",i,j,a[num[i][j]].x,a[num[i][j]].y); 101 } 102 Dinic(); 103 printf("Matrix %d\n",kase); 104 for (int i=1;i<=n;i++) 105 { 106 for (int j=1;j<=m;j++) 107 printf("%d ",a[num[i][j]].fl+1); 108 printf("\n"); 109 } 110 if (kase<T) printf("\n"); 111 } 112 return 0; 113 }
以上是关于uva 11082Matrix Decompressing(图论--网络流最大流 Dinic+拆点二分图匹配)的主要内容,如果未能解决你的问题,请参考以下文章
UVa 11082 - Matrix Decompressing(最大流)
[题解]UVa 11082 Matrix Decompressing