成都网络赛 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

你可能感兴趣的:(OO)