zoukankan      html  css  js  c++  java
  • HDU 1565 (最大流+黑白染色化二分图求最小割)

    http://acm.hdu.edu.cn/showproblem.php?pid=1565

    思路:将横纵坐标和为偶尔染白色,其他染黑色,黑点连接源点,流量为该点的值,白点连接汇点,流量为该点的值,黑白点有相邻的就连边,值为无穷大。最后求最大流,即该图的最小割。

    PS:刚开始不明白为为什么最大流会等于最小割,为什么所有的点之和减去最小割就会等于答案。

    我的理解是:整张图其实就跟连接管道一样,连接了黑点表示取了黑点那个值的流量,白点也是,而连接了相邻的黑白点求出的最大流就会是流量较小的那个的值。好比三根管道连接,流量分别是white,black,inf_max,这样求出来的肯定是min(white,black,inf_max),所以只要去掉这些割边所对应的值的和,剩下的就是答案的最大值了。

      1 /*Dinic算法求最大流*/
      2 #include<stdio.h>
      3 #include<string.h>
      4 #include<iostream>
      5 #define point_MAX 10000
      6 #define edge_MAX 100000
      7 #define INF_MAX 999999999
      8 using namespace std;
      9 struct EDGE
     10 {
     11     int to;/*指向的点*/
     12     int next;/*指向的下一条邻边*/
     13     int w;/*权值*/
     14 }edge[edge_MAX];
     15 int len;/*边的数量*/
     16 int point[point_MAX];
     17 int Vertex,Edge;
     18 int d[point_MAX];
     19 void init()/*初始化*/
     20 {
     21     len=0;
     22     memset(point,0,sizeof(point));
     23 }
     24 int add_edge(int a,int b,int w)/*添加由a指向b的权值为w的边*/
     25 {
     26     len++;
     27     edge[len].w=w;
     28     edge[len].to=b;
     29     edge[len].next=point[a];
     30     point[a]=len;
     31     return 0;/*无重边,插入*/
     32 }
     33 int bfs(int s)
     34 {
     35     int q[point_MAX],front=0,rear=1,j,t,i;
     36     q[0]=s;
     37     memset(d,-1,sizeof(d));/**/
     38     d[s]=0;
     39     while(front<rear)
     40     {
     41        t=q[front++];
     42          for(j=point[t];j;j=edge[j].next)
     43          {
     44             if(d[edge[j].to]==-1&&edge[j].w>0)
     45             {
     46              d[edge[j].to]=d[t]+1;
     47            q[rear++]=edge[j].to;/*逐层增加*/
     48         }
     49          }
     50     }
     51     if(d[Vertex]>=0)
     52        return 1;
     53     return 0;
     54 }
     55 long long min(long long a,long long b)
     56 {
     57     return a<b?a:b;
     58 }
     59 long long dinic(int t,long long sum)/*寻找增广路*/
     60 {
     61     int i,os,j;
     62     long long a;
     63     if(t==Vertex)/*如果已经找到汇点,返回sum*/
     64       return sum;
     65     os=sum;
     66     for(i=point[t];i&&sum;i=edge[i].next)
     67     {
     68        if(d[edge[i].to]==d[t]+1&&edge[i].w>0)/*可行流,即增广路*/
     69        {
     70            a=dinic(edge[i].to,min(sum,edge[i].w));
     71            edge[i].w-=a;
     72            for(j=point[edge[i].to];edge[j].to!=t;j=edge[j].next);
     73            edge[j].w+=a;/*处理反向边*/
     74            sum-=a;
     75        }
     76     }
     77     return os-sum;
     78 }
     79 long long DINIC(int s)/*DINIC算法*/
     80 {
     81      long long ans=0;
     82      while(bfs(s))/*遍历整个图,判断是否已经完成最大流*/
     83        ans+=dinic(s,INF_MAX);/*添加所能增加的流量*/
     84      return ans;
     85 }
     86 int abs(int a)
     87 {
     88     return a>0?a:(-a);
     89 }
     90 int main()
     91 {
     92      int i,j,x,y,w,S,D;
     93      int cost[25][25],num[25][25],col[25][25];
     94      while(scanf("%d",&Vertex)!=EOF)
     95      {
     96         init();
     97         int NUM=1;
     98         long long sum=0;
     99         for(i=1;i<=Vertex;i++)
    100             for(j=1;j<=Vertex;j++)
    101             {
    102                 scanf("%d",&cost[i][j]);
    103                 sum+=cost[i][j];
    104                 num[i][j]=NUM++;
    105                 if((i+j)&1)col[i][j]=1;//黑白染色,即化为二分图
    106                 else col[i][j]=0;
    107             }
    108         for(i=1;i<=Vertex;i++)
    109         {
    110             for(j=1;j<=Vertex;j++)
    111             {
    112                 int s=num[i][j];
    113                 if(col[i][j]&1)//奇数点/黑点连在源点上
    114                 {
    115                     add_edge(0,s,cost[i][j]);
    116                     add_edge(s,0,0);//反向边
    117                     for(int k=1;k<=Vertex;k++)
    118                         for(int l=1;l<=Vertex;l++)
    119                         {
    120                             if(abs(i-k)+abs(j-l)==1&&!(col[k][l]&1))
    121                             {
    122                                 //printf("%d->%d
    ",s,num[k][l]);
    123                                 add_edge(s,num[k][l],INF_MAX);
    124                                 add_edge(num[k][l],s,0);
    125                             }
    126                         }
    127                 }
    128                 else
    129                 {
    130                     add_edge(s,NUM,cost[i][j]);
    131                     add_edge(NUM,s,0);//反向边
    132                     /*for(int k=1;k<=Vertex;k++)
    133                         for(int l=1;l<=Vertex;l++)
    134                         {
    135                             if(abs(i-k)+abs(j-l)==1&&(num[k][l]&1))
    136                             {
    137                                 //printf("%d->%d
    ",s,num[k][l]);
    138                                 add_edge(num[k][l],s,INF_MAX);
    139                                 add_edge(s,num[k][l],0);
    140                             }
    141                         }*/
    142                 }
    143             }
    144         }
    145         Vertex=NUM;
    146         //cout<<"=="<<endl;
    147         cout<<sum-DINIC(0)<<endl;/*以S为源点,Vertex为汇点*/
    148      }
    149      return 0;
    150 }
    151 /*
    152 3
    153 75 15 21
    154 75 15 28
    155 34 70 5
    156 3
    157 906 864 217
    158 502 517 839
    159 996 39 29
    160 
    161 */
    View Code
  • 相关阅读:
    css文本溢出省略号
    SQL语句判断是否为今天或昨天
    git 常用命令
    SwitchHosts—hosts管理利器
    ORACLE ERP consolidation流程(一)
    R12 AR INVOICE 接口表导入
    FA模块的10个API范例
    使用dbms_profiler包测试存储过程性能
    WebADI应用到Office 2016 64-bit
    Oracle EBS主界面的Top Ten List
  • 原文地址:https://www.cnblogs.com/huzhenbo113/p/3912584.html
Copyright © 2011-2022 走看看