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&∑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 }