zoukankan      html  css  js  c++  java
  • hdu4888 最大流(构造矩阵)

    题意:
          让你构造一个矩阵,满足每一行的和,和每一列的和都等于他给的,还要判断答案是否唯一,还有一点就是矩阵内所有的数字都是[0,k]范围的。

    思路:

          这个题目看完就让我想起了hdu3338,那个题目做了好久啊!哎!对于构造矩阵还是很简单的,我们构造两个点起s点和终点e,建图如下:

    s -> 所有行       流量是当前行和

    所有行 -> 所有列  流量为k

    所有列 -> e       流量为当前列和


    这样矩阵就构造好了,如果输出答案就直接去残余网络里面找就行了,下面说一下怎么判断最大流是否唯一,其实这个我们可以通过残余网络来找,只要能在残余网络上找到环就行了,这个结论值存在于无环图中,这里说的无环图是指建图的时候的正向图是无环的,对于这个题目就是无环图,这个题目还有一个坑点,就是一开始我是从终点开始搜直接找环,没有从起点是因为起点已经满流,正向流量全是0,根本跑不懂,但是从终点跑各种超时,超时出翔了,无语了我又枚举所有终点所连接的点开始跑,还是超时,最后是枚举起点所连接的点

    开始跑的,500ms AC,我有点蛋疼,理论上对于一个环而言从哪个位置跑都可以找到环,我估计是数据里面给的 "能得到唯一答案" 的数据过多,这样就让很多正向的流量变成0,或者是不至于走了好几层才变成0,哎!这个不科学啊!


    #include<stdio.h>
    #include<string.h>
    #include<queue>
    
    #define N_node 810
    #define N_edge 350000
    #define INF 1000000000
    
    using namespace std;
    
    typedef struct
    {
       int to ,next ,cost;
    }STAR;
    
    typedef struct
    {
       int x ,t;
    }DEP;
    
    STAR E[N_edge];
    DEP xin ,tou;
    int list[N_node] ,list1[N_node] ,tot;
    int deep[N_node] ,map[405][405];
    
    void add(int a ,int b ,int c)
    {
       E[++tot].to = b;
       E[tot].cost = c;
       E[tot].next = list[a];
       list[a] = tot;
       E[++tot].to = a;
       E[tot].cost = 0;
       E[tot].next = list[b];
       list[b] = tot;
    }
    
    int minn(int x ,int y)
    {
       return x < y ? x : y;
    }
    
    
    bool bfs_deep(int s ,int t ,int n)
    { 
        xin.x = s ,xin.t = 0;
        queue<DEP>q; q.push(xin);
        memset(deep ,255 ,sizeof(deep));
        deep[s] = 0;
        while(!q.empty())
        {
             tou = q.front();
             q.pop();
             for(int k = list[tou.x] ;k ;k = E[k].next)
             {
                xin.x = E[k].to;
                xin.t = tou.t + 1;
                if(deep[xin.x] == -1 && E[k].cost)
                {
                   deep[xin.x] = xin.t;
                   q.push(xin);
                }
             }
          }
          for(int i = 0 ;i <= n ;i ++)
          list1[i] = list[i];
          return deep[t] != -1;
    }
    
    int DFS(int s ,int t ,int flow)
    {
       if(s == t) return flow;
       int nowflow = 0;
       for(int k = list1[s] ;k ;k = E[k].next)
       {
          list1[s] = k;
          int c = E[k].cost;
          int to = E[k].to;
          if(!c || deep[to] != deep[s] + 1) continue;
          int tmp = DFS(to ,t ,minn(c ,flow - nowflow));
          nowflow += tmp;
          E[k].cost -= tmp;
          E[k^1].cost += tmp;
          if(nowflow == flow) break;
       }
       if(!nowflow) deep[s] = 0;
       return nowflow;
    }
        
    int DINIC(int s ,int t ,int n)
    {
       int ans = 0;
       while(bfs_deep(s ,t ,n))
       {
          ans += DFS(s ,t ,INF);
       }
       return ans;
    }
    
    int mark_r;
    int mark[N_node];
    void DFS_R(int from ,int s)
    {
       for(int k = list[s] ;k && !mark_r ;k = E[k].next)
       {
          int to = E[k].to;
          if(k == (from ^ 1) || !E[k].cost) continue;
          if(mark[to]) mark_r = 1;
          mark[to] = 1;
          if(!mark_r) DFS_R(k ,to);
          mark[to] = 0;
       }
    }
          
    int main ()
    {
       int n ,m ,i ,j ,k ,num;
       int s1 ,s2;
       while(~scanf("%d %d %d" ,&n ,&m ,&k))
       {
          memset(list ,0 ,sizeof(list)) ,tot = 1;
          int mkk = 0;
          for(s1 = 0 ,i = 1 ;i <= n ;i ++)
          {
             scanf("%d" ,&num);
             add(0 ,i ,num);
             if(k * m < num) mkk = 1;
             s1 += num;
          }
          for(s2 = 0 ,i = 1 ;i <= m ;i ++)
          {
             scanf("%d" ,&num);
             add(i + n ,n + m + 1 ,num);
             if(k * n < num) mkk = 1;
             s2 += num;
          }
          if(s1 != s2 || mkk)
          {
             puts("Impossible"); continue;
          }
          int mk = tot + 1;
          for(i = 1 ;i <= n ;i ++)
          for(j = 1 ;j <= m ;j ++)
          add(i ,j + n ,k);
          int sum = DINIC(0 ,n + m + 1 ,n + m + 1);
          if(sum != s1)
          {
             puts("Impossible"); continue;
          }
          mark_r = 0;
          memset(mark , 0 ,sizeof(mark));
          mark[n+m+1] = 1;
          for(i = 1 ;i <= n ;i ++)
          {
             DFS_R(0 ,i);
             if(mark_r) break;
          }
          if(mark_r)
          {
             puts("Not Unique");continue;
          }
          puts("Unique");
          int t = 0;
          for(i = mk ;i <= tot ;i += 2)
          {
             printf("%d" ,k - E[i].cost);
             if(++t % m == 0) puts("");
             else printf(" ");
          }       
       }
       return 0;
    }
          
          
          
          
          
             
    
    

  • 相关阅读:
    【待整理】转义字符
    关系运算符 与 逻辑运算符
    浏览器相关
    正则表达式
    样式定义——多重浏览器
    事件
    属性定义
    数组
    日期
    构造函数
  • 原文地址:https://www.cnblogs.com/csnd/p/12062912.html
Copyright © 2011-2022 走看看