成都网络赛 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。然后问题转换为求最大流问题

View Code
  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

View Code
  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

posted @ 2012-09-16 17:02  yejinru  阅读(1707)  评论(0编辑  收藏  举报