• 【uva 11082】Matrix 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
    ",i,j,a[num[i][j]].x,a[num[i][j]].y);
    101         }
    102       Dinic();
    103       printf("Matrix %d
    ",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("
    ");
    109       }
    110       if (kase<T) printf("
    ");
    111     }
    112     return 0;
    113 }
  • 相关阅读:
    bzoj 3531 [Sdoi2014]旅行(树链剖分,线段树)
    bzoj 2243 [SDOI2011]染色(树链剖分,线段树)
    spoj 375 Query on a tree(树链剖分,线段树)
    bzoj 2618 2618: [Cqoi2006]凸多边形(半平面交)
    C++中int型与char型相互转换的问题
    408 二进制求和
    407 加一
    斐波那契数列几种算法及时间复杂度分析
    397 Longest Continuous Increasing Subsequence
    376 二叉树的路径和
  • 原文地址:https://www.cnblogs.com/konjak/p/6049534.html
Copyright © 2020-2023  润新知