首页 > 代码库 > HDU 4289 Control (最大流+拆点)

HDU 4289 Control (最大流+拆点)

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

题目讲的是有一些恐怖分子要从S市去往D市,要求在一些城市中安排特工,保证一定能够抓住恐怖分子,因为安排特工需要一定的费用,所以希望找出最小的花费。

思路:可以把每个城市,即每个点拆分成进来的点和出去的点,如x点分成x和x+n,两点连接的边权值为x点上安排特工的费用。而如果x和y两点有连线,则连接x+n,y,然后求从S市到达D市的最大流。之所以能这样求,是因为在求最大流的过程中每次所更新的流量是所有边中最小的,这样最小流量的边就是每个点拆分开的两点之间的连线,这样求的过程中对最大流有限制的就是所有点上的花费了。

  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  87 int main() 88 { 89      int i,j,x,y,w,S,D; 90      int cost[205]; 91      while(scanf("%d%d",&Vertex,&Edge)!=EOF) 92      { 93         init(); 94         memset(cost,0,sizeof(cost)); 95         scanf("%d%d",&S,&D); 96         for(i=1;i<=Vertex;i++) 97         { 98             scanf("%d",&cost[i]); 99             add_edge(i,i+Vertex,cost[i]);100             add_edge(i+Vertex,i,0);101         }102         for(i=0;i<Edge;i++)103         {104            scanf("%d%d",&x,&y);105            add_edge(x+Vertex,y,INF_MAX);106            add_edge(y,x+Vertex,0);107            add_edge(y+Vertex,x,INF_MAX);/*添加反向边*/108            add_edge(x,y+Vertex,0);109         }110         Vertex=D+Vertex;111         //cout<<"=="<<endl;112         printf("%lld\n",DINIC(S));/*以S为源点,Vertex为汇点*/113      }114      return 0;115 }
View Code