成都网络赛 1002 Control 1005 Food
若有错,请指出^_^
6775504 | 2012-09-16 17:05:39 | Accepted | 4292 | 125MS | 2436K | 3010 B | G++ | yejinru |
6775496 | 2012-09-16 17:05:08 | Accepted | 4289 | 78MS | 1488K | 2452 B | G++ | yejinru |
1002 Control
题目:
给出歹徒的起点、终点以及每个经过的节点的权值,问如何安排警察在节点上拦截歹徒,使得歹徒总会被逮获,并且使得费用最少
分析:
最小割问题,对于每个节点进行拆点操作(a,a+n两条边),流量为他的点权。然后对于边相连的情况,由于边是无向边,所以建立四条边(a+n,b),(b+n,a),流量为inf,以及他们各自的反向边(b,a+n),(a,b+n),流量为-inf。最后源点为输入的s,汇点是t+n。然后问题转换为求最大流问题
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 5 using namespace std; 6 7 const int maxn = 1005; 8 const int maxm = 100005; 9 const int inf = 2e9; 10 11 bool map[maxn][maxn]; 12 int n,s,t,m; 13 int po[maxn],tol; 14 int arc[maxn],pre[maxn],cf[maxn],dis[maxn],gap[maxn]; 15 16 struct node{ 17 int y,f,next; 18 }edge[maxm]; 19 20 void add(int x,int y,int f){ 21 edge[++tol].y = y; 22 edge[tol].f = f; 23 edge[tol].next = po[x]; 24 po[x] = tol; 25 26 edge[++tol].y = x; 27 edge[tol].f = 0; 28 edge[tol].next = po[y]; 29 po[y] = tol; 30 } 31 32 void sap(){ 33 memset(dis,0,sizeof(dis)); 34 memset(gap,0,sizeof(gap)); 35 gap[0] = n; 36 for(int i=1;i<=n;i++) 37 arc[i] = po[i]; 38 int MIN; 39 int ans = 0; 40 bool ok; 41 int aug = inf; 42 int i = s; 43 44 while(dis[s]<n){ 45 cf[i] = aug; 46 ok = false; 47 for(int j=arc[i];j;j=edge[j].next){ 48 if(edge[j].f>0&&dis[edge[j].y]+1==dis[i]){ 49 ok = true; 50 if(aug>edge[j].f) 51 aug = edge[j].f; 52 arc[i] = j; 53 i = edge[j].y; 54 pre[i] = j; 55 if(i==t){ 56 ans += aug; 57 for(;i!=s;i=edge[pre[i]^1].y){ 58 edge[pre[i]].f -= aug; 59 edge[pre[i]^1].f += aug; 60 } 61 aug = inf; 62 } 63 break; 64 } 65 } 66 if(ok) 67 continue; 68 MIN = n-1; 69 for(int j=po[i];j;j=edge[j].next) 70 if(edge[j].f>0&&dis[edge[j].y]<MIN){ 71 MIN = dis[edge[j].y]; 72 arc[i] = j; 73 } 74 if(--gap[dis[i]]==0) 75 break; 76 dis[i] = MIN+1; 77 gap[dis[i]]++; 78 if(i!=s){ 79 i = edge[pre[i]^1].y; 80 aug = cf[i]; 81 } 82 } 83 printf("%d\n",ans); 84 } 85 86 void init(){ 87 scanf("%d%d",&s,&t); 88 t = t+n; 89 memset(po,0,sizeof(po)); 90 tol = 1; 91 int x,y; 92 for(int i=1;i<=n;i++){ 93 scanf("%d",&x); 94 add(i,i+n,x); 95 } 96 while(m--){ 97 scanf("%d%d",&x,&y); 98 add(x+n,y,inf); 99 add(y+n,x,inf); 100 } 101 } 102 103 int main(){ 104 freopen("sum.in","r",stdin); 105 while(cin>>n>>m){ 106 init(); 107 n = n*2; 108 sap(); 109 } 110 return 0; 111 }
题目:
给出n个人喜欢的饮料种类以及食物种类,每个人只能取其中一种且数量为1,现在给出有f中食物以及d种饮料,以及他们各自的数量,问如何安、排食物以及饮料,使得最多的人得到一个食物以及一瓶饮料
分析:
最大流问题,对人进行拆点,拆成(a,a'),分别连上自己的边,流量为1
建立超级源点,连上每种食物,流量为每种食物的数量
建立超级汇点,连上每种饮料,流量为每种饮料的数量
最后是人与饮料以及食物连上边,分别是食物与a,饮料与a'
为什么是要拆点?因为如果没有拆点的话,只是单纯地连上人与食物、饮料的边,但是流量是不确定的,存在有人得到超过一种的食物或者饮料,所以得要限制人的流量
我的模板:
有当前弧优化、GAP优化,实际效果很好,模板详解
http://www.cnblogs.com/yejinru/archive/2012/09/16/2687633.html
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 5 using namespace std; 6 7 const int X = 305; 8 const int maxn = 1005; 9 const int maxm = 200000; 10 const int inf = 1e9; 11 #define debug puts("here"); 12 13 int n,m,s,t; 14 int gap[maxn],arc[maxn],cf[maxn],dis[maxn],pre[maxn]; 15 int po[maxn],tol; 16 char str[X]; 17 18 struct node{ 19 int y,f,next; 20 }edge[maxm]; 21 22 23 void sap(){ 24 memset(dis,0,sizeof(dis)); 25 memset(gap,0,sizeof(gap)); 26 gap[0] = n; 27 for(int i=1;i<=n;i++) 28 arc[i] = po[i]; 29 int MIN; 30 int ans = 0; 31 bool ok; 32 int aug = inf; 33 int i = s; 34 35 while(dis[s]<n){ 36 cf[i] = aug; 37 ok = false; 38 for(int j=arc[i];j;j=edge[j].next){ 39 if(edge[j].f>0&&dis[edge[j].y]+1==dis[i]){ 40 ok = true; 41 if(aug>edge[j].f) 42 aug = edge[j].f; 43 arc[i] = j; 44 i = edge[j].y; 45 pre[i] = j; 46 if(i==t){ 47 ans += aug; 48 for(;i!=s;i=edge[pre[i]^1].y){ 49 edge[pre[i]].f -= aug; 50 edge[pre[i]^1].f += aug; 51 } 52 aug = inf; 53 } 54 break; 55 } 56 } 57 if(ok) 58 continue; 59 MIN = n-1; 60 for(int j=po[i];j;j=edge[j].next) 61 if(edge[j].f>0&&dis[edge[j].y]<MIN){ 62 MIN = dis[edge[j].y]; 63 arc[i] = j; 64 } 65 if(--gap[dis[i]]==0) 66 break; 67 dis[i] = MIN+1; 68 gap[dis[i]]++; 69 if(i!=s){ 70 i = edge[pre[i]^1].y; 71 aug = cf[i]; 72 } 73 } 74 printf("%d\n",ans); 75 } 76 77 void add(int x,int y,int f){ 78 edge[++tol].y = y; 79 edge[tol].f = f; 80 edge[tol].next = po[x]; 81 po[x] = tol; 82 83 edge[++tol].y = x; 84 edge[tol].f = 0; 85 edge[tol].next = po[y]; 86 po[y] = tol; 87 } 88 89 void init(int f,int d){ 90 memset(po,0,sizeof(po)); 91 tol = 1; 92 s = 2*n+f+d+1; 93 t = s+1; 94 int x,y; 95 for(int i=1;i<=f;i++){ 96 scanf("%d",&x); 97 add(s,i,x); 98 } 99 for(int i=1;i<=d;i++){ 100 scanf("%d",&x); 101 add(i+f+2*n,t,x); 102 } 103 104 for(int i=1;i<=n;i++){ 105 add(i+f,i+f+n,1); 106 scanf("%s",str); 107 x = i+f; 108 for(int j=0;str[j];j++){ 109 if(str[j]=='Y'){ 110 y = j+1; 111 add(y,x,1); 112 } 113 } 114 } 115 116 for(int i=1;i<=n;i++){ 117 scanf("%s",str); 118 x = i+f+n; 119 for(int j=0;str[j];j++){ 120 if(str[j]=='Y'){ 121 y = j+2*n+f+1; 122 add(x,y,1); 123 } 124 } 125 } 126 } 127 128 int main(){ 129 freopen("sum.in","r",stdin); 130 int f,d; 131 while(cin>>n>>f>>d){ 132 init(f,d); 133 n = t; 134 sap(); 135 } 136 return 0; 137 }
网络流练习
在hust上 http://acm.hust.edu.cn:8080/judge/contest/toListContest.action 的Search中键入"网络流"或者"最大流"之类的就有很多了
http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=3184#overview
http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=6377#overview