码迷,mamicode.com
首页 > 其他好文 > 详细

网络流24题

时间:2015-11-23 18:34:28      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:

这次的题全是老爷题yooo~

  • 搭配飞行员

    普通二分图,,,源点向正飞行员连1的边,有取向 :->的正副飞行员连1或inf的边,副飞行员和汇点连1的边,然后跑最大流

    源/汇点向飞行员连的边一定要单独建= =

技术分享
 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 #define maxn 105
 7 #define maxm 3000
 8 #define inf 0x3f3f3f3f
 9 int cnt,v[maxm<<1],w[maxm<<1],next[maxm<<1],first[maxn];
10 int SSS,TTT,q[maxn],dep[maxn];
11 void add(int st,int end,int val){
12     v[cnt]=end;w[cnt]=val;next[cnt]=first[st];first[st]=cnt++;
13     v[cnt]=st;w[cnt]=0;next[cnt]=first[end];first[end]=cnt++;
14 }
15 bool bfs(){
16     int head=0,tail=0;
17     memset(dep,0,sizeof(dep));
18     q[++tail]=SSS;
19     dep[SSS]=1;
20     while(head<tail){
21         int x=q[++head];
22         for(int e=first[x];e!=-1;e=next[e]){
23             if(!dep[v[e]]&&w[e]>0){
24                 dep[v[e]]=dep[x]+1;
25                 q[++tail]=v[e];
26             }
27         }
28     }
29     return dep[TTT];
30 }
31 int dfs(int x,int lim){
32     if(x==TTT)return lim;
33     int lim1=lim;
34     for(int e=first[x];e!=-1;e=next[e]){
35         if(dep[v[e]]==dep[x]+1&&w[e]>0){
36             int flow=dfs(v[e],min(lim,w[e]));
37             w[e]-=flow;w[e^1]+=flow;
38             if((lim-=flow)<=0)break;
39         }
40     }
41     if(lim==lim1)dep[x]=0;
42     return lim1-lim;
43 }
44 int main(){
45     freopen("flyer.in","r",stdin);
46     freopen("flyer.out","w",stdout);
47     int n,n1,a,b;
48     memset(first,-1,sizeof(first));
49     scanf("%d%d",&n,&n1);
50     SSS=0,TTT=n+1;
51     for(int i=1;i<=n1;i++)add(SSS,i,1);
52     for(int i=n1+1;i<=n;i++)add(i,TTT,1);
53     while(scanf("%d%d",&a,&b)!=EOF)add(a,b,2);
54     int ans=0;
55     while(bfs())ans+=dfs(SSS,inf);
56     printf("%d\n",ans);
57     fclose(stdin);
58     fclose(stdout);
59     return 0;
60 }
View Code

 

  • 太空飞行计划

    最大权闭合子图,666

    源点向实验连权值为赞助额的边,实验向仪器连inf的边,仪器向汇点连权值为仪器开销的边,求出最小割。

    最小割上的实验边代表不选的实验,因为开销>赞助额,从而使实验边满载;最小割上的仪器边代表要选的仪器,因为开销<=赞助额,从而使仪器边满载

    由此可知答案为所有实验边的和减去最小割

技术分享
  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<vector>
  4 #include<ctype.h>
  5 using namespace std;
  6 #define maxn 2005
  7 #define maxm 105000
  8 #define inf 0x3f3f3f3f
  9 vector<int>poi[maxn];
 10 int cnt,v[maxm<<1],w[maxm<<1],next[maxm<<1],first[maxn],cur[maxn];
 11 int SSS,TTT,dep[maxn],q[maxn],have[maxn],you[maxn];
 12 void read(int i){    
 13     char ch=0;
 14     while(1){
 15         while(!isdigit(ch))
 16             ch=getchar();
 17         int tmp=0;
 18         while(isdigit(ch)){
 19             tmp=tmp*10+ch-0;
 20             ch=getchar();
 21         }
 22         poi[i].push_back(tmp);
 23         if(ch==\r)return;
 24     }
 25 }
 26 void add(int st,int end,int val){
 27     v[cnt]=end;w[cnt]=val;next[cnt]=first[st];first[st]=cnt++;
 28     v[cnt]=st;w[cnt]=0;next[cnt]=first[end];first[end]=cnt++;
 29 }
 30 bool bfs(){
 31     int head=0,tail=0;
 32     memset(dep,0,sizeof(dep));
 33     q[++tail]=SSS;
 34     dep[SSS]=1;
 35     while(head<tail){
 36         int x=q[++head];
 37         for(int e=first[x];e!=-1;e=next[e]){
 38             if(!dep[v[e]]&&w[e]>0){
 39                 dep[v[e]]=dep[x]+1;
 40                 q[++tail]=v[e];
 41             }
 42         }
 43     }
 44     return dep[TTT];
 45 }
 46 int dfs(int x,int lim){
 47     if(x==TTT)return lim;
 48     int lim1=lim;
 49     for(int e=cur[x];e!=-1;e=next[e]){
 50         if(dep[v[e]]==dep[x]+1&&w[e]>0){
 51             int flow=dfs(v[e],min(lim,w[e]));
 52             cur[x]=e;
 53             w[e]-=flow;w[e^1]+=flow;
 54             if((lim-=flow)<=0)break;
 55         }
 56     }
 57     if(lim==lim1)dep[x]=0;
 58     return lim1-lim;
 59 }
 60 int main(){
 61     freopen("shuttle.in","r",stdin);
 62     freopen("shuttle.out","w",stdout);
 63     int n,m,x;
 64     memset(first,-1,sizeof(first));
 65     scanf("%d%d",&n,&m);
 66     SSS=0,TTT=n+m+1;
 67     int sum=0;
 68     for(int i=1;i<=n;i++){
 69         scanf("%d",&x);
 70         sum+=x;
 71         add(SSS,i,x);
 72         read(i);
 73     }
 74     for(int i=1;i<=m;i++){
 75         scanf("%d",&x);
 76         add(i+n,TTT,x);
 77     }
 78     for(int i=1;i<=n;i++)
 79         for(int j=0;j<poi[i].size();j++)
 80             add(i,poi[i][j]+n,inf);
 81     int ans=0;
 82     while(bfs()){
 83         memcpy(cur,first,sizeof(first));
 84         ans+=dfs(SSS,inf);
 85     }
 86     for(int e=first[SSS];e!=-1;e=next[e])
 87         if(dep[v[e]])have[v[e]]=1;
 88     for(int i=1;i<=n;i++)
 89         if(have[i]){
 90             printf("%d ",i);
 91             for(int j=0;j<poi[i].size();j++)
 92                 you[poi[i][j]]=1;
 93         }
 94     printf("\n");
 95     for(int i=1;i<=m;i++)
 96         if(you[i])printf("%d ",i);
 97     printf("\n%d\n",sum-ans);
 98     fclose(stdin);
 99     fclose(stdout);
100     return 0;
101 }
View Code

 

  • 最小路径覆盖问题

    可以转化成二分图最大匹配,因为每匹配一条边就少一条路径。因为要输出方案,所以写了匈牙利。。。

    把每个点拆成两个,原图中有边的两个点之间有配对倾向。路径数为点数-最大匹配数,输出方案就可以在belong数组,或map数组上luogan

技术分享
 1 #include<stdio.h>
 2 #include<string.h>
 3 
 4 #define maxn 305
 5 #define maxm 6005
 6 int cnt,v[maxm<<1],next[maxm<<1],first[maxn];
 7 int used[maxn],belong[maxn],map[maxn],vis[maxn];
 8 
 9 void add(int st,int end){
10     v[++cnt]=end;
11     next[cnt]=first[st];
12     first[st]=cnt;
13 }
14 bool find(int x){
15     for(int e=first[x];e;e=next[e]){
16         if(!used[v[e]]){
17             used[v[e]]=1;
18             if(!belong[v[e]]||find(belong[v[e]])){
19                 belong[v[e]]=x;
20                 map[x]=v[e];
21                 return true;
22             }
23         }
24     }
25     return false;
26 }
27 int main(){
28     freopen("path3.in","r",stdin);
29     freopen("path3.out","w",stdout);
30     int n,m,a,b;
31     scanf("%d%d",&n,&m);
32     for(int i=1;i<=m;i++){
33         scanf("%d%d",&a,&b);
34         add(a,b+n);
35     }
36     int ans=0;
37     for(int i=1;i<=n;i++){
38         for(int j=n;j<=2*n;j++)used[j]=0;
39         if(find(i))ans++;
40     }
41     for(int i=1;i<=n;i++){
42         if(!vis[i]){
43             int ii=i;
44             while(ii>0){
45                 printf("%d ",ii);
46                 vis[ii]=1;
47                 ii=map[ii]-n;
48             }
49             printf("\n");
50         }
51     }
52     printf("%d\n",n-ans);
53     fclose(stdin);
54     fclose(stdout);
55     return 0;
56 }
View Code

     Dinic算法请见友链中的y7070.   http://www.cnblogs.com/y7070/p/4988800.html

网络流24题

标签:

原文地址:http://www.cnblogs.com/Ngshily/p/4988909.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!