网络流24题

[网络流24题] 搭配飞行员

★★☆   输入文件:flyer.in   输出文件:flyer.out   简单对比
时间限制:1 s   内存限制:128 MB

【问题描述】
    飞行大队有若干个来自各地的驾驶员,专门驾驶一种型号的飞机,这种飞机每架有两个驾驶员,需一个正驾驶员和一个副驾驶员。由于种种原因,例如相互配合的问题,有些驾驶员不能在同一架飞机上飞行,问如何搭配驾驶员才能使出航的飞机最多。

 
如图,假设有10个驾驶员,如图中的V1,V2,…,V10就代表达10个驾驶员,其中V1,V2,V3,V4,V5是正驾驶 员,V6,V7,V8,V9,V10是副驾驶员。如果一个正驾驶员和一个副驾驶员可以同机飞行,就在代表他们两个之间连一条线,两个人不能同机飞行,就不 连。例如V1和V7可以同机飞行,而V1和V8就不行。请搭配飞行员,使出航的飞机最多。注意:因为驾驶工作分工严格,两个正驾驶员或两个副驾驶员都不能 同机飞行.
 
【输入格式】
输入文件有若干行
第一行,两个整数n与n1,表示共有n个飞行员(2<=n<=100),其中有n1名飞行员是正驾驶员.
下面有若干行,每行有2个数字a,b。表示正驾驶员a和副驾驶员b可以同机飞行。
注:正驾驶员的编号在前,即正驾驶员的编号小于副驾驶员的编号.
【输出格式】
输出文件有一行
第一行,1个整数,表示最大起飞的飞机数。
【输入输出样例】
输入文件名: flyer.in
10 5
1 7
2 6
2 10
3 7
4 8
5 9
 
输出文件名:flyer.out
4
 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <queue>
 5 using namespace std;
 6 const int maxn=100010;
 7 const int maxm=1000010;
 8 const int INF=1000000000;
 9 int cnt,fir[maxn],to[maxm],nxt[maxm],cap[maxm];
10 int dis[maxn],gap[maxn],path[maxn],fron[maxn];
11 queue<int>q;
12 
13 struct Net_Flow{
14     int tot;
15     void Init(int tot_){
16         memset(dis,0,sizeof(dis));
17         memset(gap,0,sizeof(gap));
18         memset(fir,0,sizeof(fir));
19         cnt=1;tot=tot_;
20     }
21     void add(int a,int b,int c){
22         nxt[++cnt]=fir[a];
23         cap[cnt]=c;
24         fir[a]=cnt;
25         to[cnt]=b;
26     }
27     void addedge(int a,int b,int c){
28         add(a,b,c);add(b,a,0);
29     }
30     bool BFS(int S,int T){
31         dis[T]=1;q.push(T);
32         while(!q.empty()){
33             int x=q.front();q.pop();
34             for(int i=fir[x];i;i=nxt[i])
35                 if(!dis[to[i]]){
36                     dis[to[i]]=dis[x]+1;
37                     q.push(to[i]);
38                 }
39         }
40         return dis[S];
41     }
42     int Max_Flow(int S,int T){
43         if(!BFS(S,T))return 0;
44         for(int i=0;i<tot;i++)fron[i]=fir[i];
45         for(int i=0;i<tot;i++)gap[dis[i]]+=1;
46         int ret=0,p=S,f,Min;
47         while(dis[S]<=tot){
48             if(p==T){
49                 f=INF;
50                 while(p!=S){
51                     f=min(f,cap[path[p]]);
52                     p=to[path[p]^1];
53                 }ret+=f;p=T;
54                 while(p!=S){
55                     cap[path[p]]-=f;
56                     cap[path[p]^1]+=f;
57                     p=to[path[p]^1];
58                 }
59             }
60             
61             for(int &i=fron[p];i;i=nxt[i])
62                 if(cap[i]&&dis[to[i]]==dis[p]-1)
63                     {path[p=to[i]]=i;break;}
64             
65             if(!fron[p]){Min=tot;
66                 if(--gap[dis[p]]==0)break;
67                 for(int i=fir[p];i;i=nxt[i])
68                     if(cap[i])Min=min(Min,dis[to[i]]);
69                 gap[dis[p]=Min+1]+=1;fron[p]=fir[p];
70                 if(p!=S)p=to[path[p]^1];    
71             }        
72         }
73         return ret;
74     }
75 }ISAP;
76 
77 int main(){
78     freopen("flyer.in","r",stdin);
79     freopen("flyer.out","w",stdout);
80     int n,m,S,T,a,b;
81     scanf("%d%d",&n,&m);S=0;
82     ISAP.Init(n+2);T=n+1;
83     for(int i=1;i<=n;i++){
84         if(i<=m)ISAP.addedge(S,i,1);
85         else ISAP.addedge(i,T,1);
86     }
87     while(true){
88         if(scanf("%d%d",&a,&b)==EOF)
89             break;
90         ISAP.addedge(a,b,1);    
91     }
92     printf("%d\n",ISAP.Max_Flow(S,T));
93     return 0;
94 }

 

[网络流24题] 太空飞行计划

★★☆   输入文件:shuttle.in   输出文件:shuttle.out   简单对比
时间限制:1 s   内存限制:128 MB

【问题描述】

W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={ I1I2,…,I}。实验E需要用到的仪器是I的子集RjI。配置仪器I的费用为c美元。实验E的赞助商已同意为该实验结果支付p美元。W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。

【编程任务】

对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。

【数据输入】

第1行有2个正整数m和n(m,n <= 100)。m是实验数,n是仪器数。接下来的m行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。最后一行的n个数是配置每个仪器的费用。

【结果输出】

第1行是实验编号;第2行是仪器编号;最后一行是净收益。

【输入文件示例】shuttle.in

2 3
10 1 2
25 2 3
5 6 7

【输出文件示例】shuttle.out

1 2
1 2 3
17
  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <queue>
  5 using namespace std;
  6 const int maxn=100010;
  7 const int maxm=1000010;
  8 const int INF=1000000000;
  9 int cnt,fir[maxn],to[maxm],nxt[maxm],cap[maxm];
 10 int dis[maxn],gap[maxn],path[maxn],fron[maxn];
 11 bool a[maxn],b[maxn];
 12 queue<int>q;
 13 int n,m,S,T,tot=0;
 14 struct Net_Flow{
 15     int tot;
 16     void Init(int tot_){
 17         memset(dis,0,sizeof(dis));
 18         memset(gap,0,sizeof(gap));
 19         memset(fir,0,sizeof(fir));
 20         cnt=1;tot=tot_;
 21     }
 22     void add(int a,int b,int c){
 23         nxt[++cnt]=fir[a];
 24         cap[cnt]=c;
 25         fir[a]=cnt;
 26         to[cnt]=b;
 27     }
 28     void addedge(int a,int b,int c){
 29         add(a,b,c);add(b,a,0);
 30     }
 31     bool BFS(int S,int T){
 32         dis[T]=1;q.push(T);
 33         while(!q.empty()){
 34             int x=q.front();q.pop();
 35             for(int i=fir[x];i;i=nxt[i])
 36                 if(!dis[to[i]]){
 37                     dis[to[i]]=dis[x]+1;
 38                     q.push(to[i]);
 39                 }
 40         }
 41         return dis[S];
 42     }
 43     int Max_Flow(int S,int T){
 44         if(!BFS(S,T))return 0;
 45         for(int i=0;i<tot;i++)fron[i]=fir[i];
 46         for(int i=0;i<tot;i++)gap[dis[i]]+=1;
 47         int ret=0,p=S,f,Min;
 48         while(dis[S]<=tot){
 49             if(p==T){
 50                 f=INF;
 51                 while(p!=S){
 52                     f=min(f,cap[path[p]]);
 53                     p=to[path[p]^1];
 54                 }ret+=f;p=T;
 55                 while(p!=S){
 56                     cap[path[p]]-=f;
 57                     cap[path[p]^1]+=f;
 58                     p=to[path[p]^1];
 59                 }
 60             }
 61             
 62             for(int &i=fron[p];i;i=nxt[i])
 63                 if(cap[i]&&dis[to[i]]==dis[p]-1)
 64                     {path[p=to[i]]=i;break;}
 65             
 66             if(!fron[p]){Min=tot;
 67                 if(--gap[dis[p]]==0)break;
 68                 for(int i=fir[p];i;i=nxt[i])
 69                     if(cap[i])Min=min(Min,dis[to[i]]);
 70                 gap[dis[p]=Min+1]+=1;fron[p]=fir[p];
 71                 if(p!=S)p=to[path[p]^1];    
 72             }        
 73         }
 74         return ret;
 75     }
 76     bool vis[maxn];
 77     void DFS(int p){
 78         vis[p]=1;
 79         if(p<=n)a[p]=1;else b[p]=1;
 80         for(int i=fir[p];i;i=nxt[i])
 81             if(cap[i]&&!vis[to[i]])DFS(to[i]);
 82     }
 83     int Solve(int S,int T){
 84         int ret=Max_Flow(S,T);DFS(S);
 85         for(int i=n+1;i<=n+m;i++)
 86             if(b[i])printf("%d ",i-n);
 87         printf("\n");    
 88         for(int i=1;i<=n;i++)
 89             if(a[i])printf("%d ",i);
 90         printf("\n");
 91         return ret;            
 92     }
 93 }ISAP;
 94 
 95 int main(){
 96     freopen("shuttle.in","r",stdin);
 97     freopen("shuttle.out","w",stdout);
 98     scanf("%d%d",&m,&n);
 99     S=0;T=n+m+1;ISAP.Init(T+1);
100     for(int i=n+1;i<=n+m;i++){
101         int v,a;char c;
102         scanf("%d",&v);tot+=v;
103         ISAP.addedge(S,i,v);
104         c=getchar();
105         while(c!='\r'){
106             scanf("%d",&a);
107             ISAP.addedge(i,a,INF);
108             c=getchar();
109         }
110     }
111     for(int i=1,v;i<=n;i++){
112         scanf("%d",&v);
113         ISAP.addedge(i,T,v);
114     }
115     printf("%d\n",tot-ISAP.Solve(S,T));
116     return 0;
117 }

 

[网络流24题] 最小路径覆盖问题

★★   输入文件:path3.in   输出文件:path3.out   评测插件
时间限制:1 s   内存限制:128 MB 算法实现题8-3 最小路径覆盖问题(习题8-13)

´问题描述:

给定有向图G=(V,E)。设P是G的一个简单路(顶点不相交)的集合。如果V中每个
顶点恰好在P的一条路上,则称P是G的一个路径覆盖。P中路径可以从V的任何一个顶
点开始,长度也是任意的,特别地,可以为0。G的最小路径覆盖是G的所含路径条数最少
的路径覆盖。
设计一个有效算法求一个有向无环图G的最小路径覆盖。

提示:

设V={1,2,...  ,n},构造网络G1=(V1,E1)如下:


每条边的容量均为1。求网络G1的(x0,y0)最大流。

´编程任务:

对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。

´数据输入:

由文件input.txt提供输入数据。文件第1行有2个正整数n和m。n是给定有向无环图
G的顶点数,m是G的边数。接下来的m行,每行有2个正整数i 和j,表示一条有向边(i,j)。

´结果输出:

程序运行结束时,将最小路径覆盖输出到文件output.txt中。从第1行开始,每行输出

一条路径。文件的最后一行是最少路径数。


输入文件示例

input.txt

11 12
1 2
1 3
1 4
2 5
3 6
4 7
5 8
6 9
7 10
8 11
9 11
10 11


 输出文件示例

output.txt


1 4 7 10 11
2 5 8
3 6 9
3



数据范围:

1<=n<=150,1<=m<=6000

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <queue>
  5 using namespace std;
  6 const int maxn=100010;
  7 const int maxm=1000010;
  8 const int INF=1000000000;
  9 int cnt,fir[maxn],to[maxm],nxt[maxm],cap[maxm];
 10 int dis[maxn],gap[maxn],path[maxn],fron[maxn];
 11 int id[maxm],G[maxn];
 12 queue<int>q;
 13 int n,m,S,T,tot=0;
 14 struct Net_Flow{
 15     int tot;
 16     void Init(int tot_){
 17         memset(dis,0,sizeof(dis));
 18         memset(gap,0,sizeof(gap));
 19         memset(fir,0,sizeof(fir));
 20         cnt=1;tot=tot_;
 21     }
 22     void add(int a,int b,int c,int p){
 23         nxt[++cnt]=fir[a];
 24         cap[cnt]=c;
 25         fir[a]=cnt;
 26         to[cnt]=b;
 27         id[cnt]=p;
 28     }
 29     void addedge(int a,int b,int c,int p){
 30         add(a,b,c,p);add(b,a,0,p);
 31     }
 32     bool BFS(int S,int T){
 33         dis[T]=1;q.push(T);
 34         while(!q.empty()){
 35             int x=q.front();q.pop();
 36             for(int i=fir[x];i;i=nxt[i])
 37                 if(!dis[to[i]]){
 38                     dis[to[i]]=dis[x]+1;
 39                     q.push(to[i]);
 40                 }
 41         }
 42         return dis[S];
 43     }
 44     int Max_Flow(int S,int T){
 45         if(!BFS(S,T))return 0;
 46         for(int i=0;i<tot;i++)fron[i]=fir[i];
 47         for(int i=0;i<tot;i++)gap[dis[i]]+=1;
 48         int ret=0,p=S,f,Min;
 49         while(dis[S]<=tot){
 50             if(p==T){
 51                 f=INF;
 52                 while(p!=S){
 53                     f=min(f,cap[path[p]]);
 54                     p=to[path[p]^1];
 55                 }ret+=f;p=T;
 56                 while(p!=S){
 57                     cap[path[p]]-=f;
 58                     cap[path[p]^1]+=f;
 59                     p=to[path[p]^1];
 60                 }
 61             }
 62             
 63             for(int &i=fron[p];i;i=nxt[i])
 64                 if(cap[i]&&dis[to[i]]==dis[p]-1)
 65                     {path[p=to[i]]=i;break;}
 66             
 67             if(!fron[p]){Min=tot;
 68                 if(--gap[dis[p]]==0)break;
 69                 for(int i=fir[p];i;i=nxt[i])
 70                     if(cap[i])Min=min(Min,dis[to[i]]);
 71                 gap[dis[p]=Min+1]+=1;fron[p]=fir[p];
 72                 if(p!=S)p=to[path[p]^1];    
 73             }        
 74         }
 75         return ret;
 76     }
 77     int vis[maxn];
 78     int Solve(int S,int T){
 79         int ret=0;
 80         Max_Flow(S,T);
 81         for(int x=1;x<=n;x++)
 82             for(int i=fir[x];i;i=nxt[i])
 83                 if(to[i]>n&&cap[i]==0)
 84                     {G[x]=to[i]-n;break;}
 85                     
 86         for(int i=1;i<=n;i++)
 87             if(!vis[i]){
 88                 int p=i;
 89                 while(p){
 90                     vis[p]=1;
 91                     printf("%d ",p);
 92                     p=G[p];
 93                 }ret+=1;
 94                 printf("\n");
 95             }        
 96         return ret;        
 97     }
 98 }ISAP;
 99 
100 int main(){
101     freopen("path3.in","r",stdin);
102     freopen("path3.out","w",stdout);
103     scanf("%d%d",&n,&m);
104     S=0;T=2*n+1;ISAP.Init(T+1);
105     for(int i=1;i<=n;i++){
106         ISAP.addedge(S,i,1,0);
107         ISAP.addedge(i+n,T,1,0);
108     }
109     for(int i=1,a,b;i<=m;i++){
110         scanf("%d%d",&a,&b);
111         ISAP.addedge(a,b+n,1,i);
112     }
113     printf("%d\n",ISAP.Solve(S,T));
114     return 0;
115 }

 

[网络流24题]魔术球问题

★★☆   输入文件:balla.in   输出文件:balla.out   简单对比
时间限制:1 s   内存限制:128 MB

问题描述:
假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为 1,2,3,4......的球。
(1)每次只能在某根柱子的最上面放球。
(2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。
试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可
放11个球。
´编程任务:
对于给定的n,计算在 n根柱子上最多能放多少个球。

´数据输入:
文件第1 行有 1个正整数n,表示柱子数。
´结果输出:
文件的第一行是球数。

数据规模

n<=60  保证答案小于1600

输入文件示例

4

输出文件示例

11

方案如下

1 8
2 7 9
3 6 10
4 5 11

每一行表示一个柱子上的球

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <queue>
  5 using namespace std;
  6 const int maxn=100010;
  7 const int maxm=1000010;
  8 const int INF=1000000000;
  9 int cnt=1,fir[maxn],to[maxm],nxt[maxm],cap[maxm];
 10 int dis[maxn],gap[maxn],path[maxn],fron[maxn];
 11 queue<int>q;
 12 int n,m,S,T,tot=0;
 13 struct Net_Flow{
 14     int tot;
 15     void Init(int tot_){
 16         memset(dis,0,sizeof(dis));
 17         memset(gap,0,sizeof(gap));
 18         tot=tot_;
 19     }
 20     void add(int a,int b,int c){
 21         nxt[++cnt]=fir[a];
 22         cap[cnt]=c;
 23         fir[a]=cnt;
 24         to[cnt]=b;
 25     }
 26     void addedge(int a,int b,int c){
 27         add(a,b,c);add(b,a,0);
 28     }
 29     bool BFS(int S,int T){
 30         dis[T]=1;q.push(T);
 31         while(!q.empty()){
 32             int x=q.front();q.pop();
 33             for(int i=fir[x];i;i=nxt[i])
 34                 if(!dis[to[i]]){
 35                     dis[to[i]]=dis[x]+1;
 36                     q.push(to[i]);
 37                 }
 38         }
 39         return dis[S];
 40     }
 41     int Max_Flow(int S,int T){
 42         if(!BFS(S,T))return 0;
 43         for(int i=0;i<tot;i++)fron[i]=fir[i];
 44         for(int i=0;i<tot;i++)gap[dis[i]]+=1;
 45         int ret=0,p=S,f,Min;
 46         while(dis[S]<=tot){
 47             if(p==T){
 48                 f=INF;
 49                 while(p!=S){
 50                     f=min(f,cap[path[p]]);
 51                     p=to[path[p]^1];
 52                 }ret+=f;p=T;
 53                 while(p!=S){
 54                     cap[path[p]]-=f;
 55                     cap[path[p]^1]+=f;
 56                     p=to[path[p]^1];
 57                 }
 58             }
 59             
 60             for(int &i=fron[p];i;i=nxt[i])
 61                 if(cap[i]&&dis[to[i]]==dis[p]-1)
 62                     {path[p=to[i]]=i;break;}
 63             
 64             if(!fron[p]){Min=tot;
 65                 if(--gap[dis[p]]==0)break;
 66                 for(int i=fir[p];i;i=nxt[i])
 67                     if(cap[i])Min=min(Min,dis[to[i]]);
 68                 gap[dis[p]=Min+1]+=1;fron[p]=fir[p];
 69                 if(p!=S)p=to[path[p]^1];    
 70             }        
 71         }
 72         return ret;
 73     }
 74     int sqr[maxn];
 75     int Solve(int S,int T){
 76         for(int i=1;i*i<4001;i++)sqr[i*i]=1;  
 77         for(int t=1;t<4001;t++){ 
 78             Init(t*2+1);
 79             for(int i=2;i<cnt;i+=2){
 80                 cap[i]=1;
 81                 cap[i+1]=0;
 82             }
 83             addedge(S,t*2,1);
 84             addedge(t*2+1,T,1);  
 85             for(int i=1;i<t;i++)
 86                 if(sqr[i+t])addedge(i*2,t*2+1,1);
 87             if(t-Max_Flow(S,T)>n)return t-1;
 88         }
 89     }
 90 }ISAP;
 91 
 92 
 93 int main(){
 94     freopen("balla.in","r",stdin);
 95     freopen("balla.out","w",stdout);
 96     int S,T;
 97     scanf("%d",&n);S=0;T=1;  
 98     printf("%d\n",ISAP.Solve(S,T)); 
 99     return 0;
100 }

 

[网络流24题] 圆桌聚餐

★★   输入文件:roundtable.in   输出文件:roundtable.out   评测插件
时间限制:1 s   内存限制:128 MB

«问题描述:

 

假设有来自m 个不同单位的代表参加一次国际会议。每个单位的代表数分别为

 

ri(i=1,2,3...m), 。会议餐厅共有n张餐桌,每张餐桌可容纳c i(i=1,2...n) 个代表就餐。

 

为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。试设计一个算法,

 

给出满足要求的代表就餐方案。

 

«编程任务:

 

对于给定的代表数和餐桌数以及餐桌容量,编程计算满足要求的代表就餐方案。

 

«数据输入:

 

由文件roundtable.in提供输入数据。文件第1行有2 个正整数m和n,m表示单位数,n表

 

示餐桌数,1<=m<=150, 1<=n<=270。文件第2 行有m个正整数,分别表示每个单位的代表

 

数。文件第3 行有n个正整数,分别表示每个餐桌的容量。

 

«结果输出:

 

程序运行结束时,将代表就餐方案输出到文件roundtable.out中。如果问题有解,在文件第

 

1 行输出1,否则输出0。接下来的m行给出每个单位代表的就餐桌号。如果有多个满足要

 

求的方案,只要输出1 个方案。

 

输入文件示例 输出文件示例

 

roundtable.in

 


4 5
4 5 3 5
3 5 2 6 4
roundtable.out


1
1 2 4 5
1 2 3 4 5
2 4 5
1 2 3 4 5
  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <queue>
  5 using namespace std;
  6 const int maxn=100010;
  7 const int maxm=1000010;
  8 const int INF=1000000000;
  9 int n,m,cnt,fir[maxn],to[maxm],nxt[maxm],cap[maxm];
 10 int dis[maxn],gap[maxn],path[maxn],fron[maxn];
 11 queue<int>q;
 12 
 13 struct Net_Flow{
 14     int tot;
 15     void Init(int tot_){
 16         memset(dis,0,sizeof(dis));
 17         memset(gap,0,sizeof(gap));
 18         memset(fir,0,sizeof(fir));
 19         cnt=1;tot=tot_;
 20     }
 21     void add(int a,int b,int c){
 22         nxt[++cnt]=fir[a];
 23         cap[cnt]=c;
 24         fir[a]=cnt;
 25         to[cnt]=b;
 26     }
 27     void addedge(int a,int b,int c){
 28         add(a,b,c);add(b,a,0);
 29     }
 30     bool BFS(int S,int T){
 31         dis[T]=1;q.push(T);
 32         while(!q.empty()){
 33             int x=q.front();q.pop();
 34             for(int i=fir[x];i;i=nxt[i])
 35                 if(!dis[to[i]]){
 36                     dis[to[i]]=dis[x]+1;
 37                     q.push(to[i]);
 38                 }
 39         }
 40         return dis[S];
 41     }
 42     int Max_Flow(int S,int T){
 43         if(!BFS(S,T))return 0;
 44         for(int i=0;i<tot;i++)fron[i]=fir[i];
 45         for(int i=0;i<tot;i++)gap[dis[i]]+=1;
 46         int ret=0,p=S,f,Min;
 47         while(dis[S]<=tot){
 48             if(p==T){
 49                 f=INF;
 50                 while(p!=S){
 51                     f=min(f,cap[path[p]]);
 52                     p=to[path[p]^1];
 53                 }ret+=f;p=T;
 54                 while(p!=S){
 55                     cap[path[p]]-=f;
 56                     cap[path[p]^1]+=f;
 57                     p=to[path[p]^1];
 58                 }
 59             }
 60             
 61             for(int &i=fron[p];i;i=nxt[i])
 62                 if(cap[i]&&dis[to[i]]==dis[p]-1)
 63                     {path[p=to[i]]=i;break;}
 64             
 65             if(!fron[p]){Min=tot;
 66                 if(--gap[dis[p]]==0)break;
 67                 for(int i=fir[p];i;i=nxt[i])
 68                     if(cap[i])Min=min(Min,dis[to[i]]);
 69                 gap[dis[p]=Min+1]+=1;fron[p]=fir[p];
 70                 if(p!=S)p=to[path[p]^1];    
 71             }        
 72         }
 73         return ret;
 74     }
 75     void Solve(){
 76         for(int x=1;x<=m;x++){
 77             for(int i=fir[x];i;i=nxt[i])
 78                 if(to[i]>m&&cap[i]==0)
 79                     printf("%d ",to[i]-m);
 80             printf("\n");    
 81         }
 82     }
 83     
 84 }ISAP;
 85 
 86 int main(){
 87     freopen("roundtable.in","r",stdin);
 88     freopen("roundtable.out","w",stdout);
 89     int S,T,sum=0;
 90     scanf("%d%d",&m,&n);
 91     S=0;T=n+m+1;ISAP.Init(T+1);
 92     for(int i=1,v;i<=m;i++){
 93         scanf("%d",&v);sum+=v;
 94         ISAP.addedge(S,i,v);
 95     }
 96     
 97     for(int i=m+1,v;i<=m+n;i++){
 98         scanf("%d",&v);
 99         ISAP.addedge(i,T,v);
100     }
101     
102     for(int i=1;i<=m;i++)
103         for(int j=m+1;j<=n+m;j++)
104             ISAP.addedge(i,j,1);
105        
106     if(ISAP.Max_Flow(S,T)==sum){
107         printf("1\n");
108         ISAP.Solve();
109     }
110     else printf("0\n");
111     return 0;
112 }

 

[网络流24题] 最长递增子序列

★★★☆   输入文件:alis.in   输出文件:alis.out   简单对比
时间限制:1 s   内存限制:128 MB «问题描述:
给定正整数序列x1,..., xn。
(1)计算其最长递增子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长
度为s的递增子序列。
«编程任务:
设计有效算法完成(1)(2)(3)提出的计算任务。
«数据输入:
由文件alis.in提供输入数据。文件第1 行有1个正整数n(n<=500),表示给定序列的长度。接
下来的1 行有n个正整数x1,..., xn。

«结果输出:
程序运行结束时,将任务(1)(2)(3)的解答输出到文件alis.out中。第1 行是最长
递增子序列的长度s。第2行是可取出的长度为s 的递增子序列个数。第3行是允许在取出
的序列中多次使用x1和xn时可取出的长度为s 的递增子序列个数。
输入文件示例 输出文件示例
alis.in
4

3 6 2 5

alis.out

2
2
3

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <queue>
  5 using namespace std;
  6 const int maxn=100010;
  7 const int maxm=1000010;
  8 const int INF=1000000000;
  9 int cnt,fir[maxn],to[maxm],nxt[maxm],cap[maxm];
 10 int dis[maxn],gap[maxn],path[maxn],fron[maxn];
 11 queue<int>q;
 12 
 13 struct Net_Flow{
 14     int tot;
 15     void Init(int tot_){
 16         memset(dis,0,sizeof(dis));
 17         memset(gap,0,sizeof(gap));
 18         memset(fir,0,sizeof(fir));
 19         cnt=1;tot=tot_;
 20     }
 21     void add(int a,int b,int c){
 22         nxt[++cnt]=fir[a];
 23         cap[cnt]=c;
 24         fir[a]=cnt;
 25         to[cnt]=b;
 26     }
 27     void addedge(int a,int b,int c){
 28         add(a,b,c);add(b,a,0);
 29     }
 30     bool BFS(int S,int T){
 31         dis[T]=1;q.push(T);
 32         while(!q.empty()){
 33             int x=q.front();q.pop();
 34             for(int i=fir[x];i;i=nxt[i])
 35                 if(!dis[to[i]]){
 36                     dis[to[i]]=dis[x]+1;
 37                     q.push(to[i]);
 38                 }
 39         }
 40         return dis[S];
 41     }
 42     int Max_Flow(int S,int T){
 43         if(!BFS(S,T))return 0;
 44         for(int i=0;i<tot;i++)fron[i]=fir[i];
 45         for(int i=0;i<tot;i++)gap[dis[i]]+=1;
 46         int ret=0,p=S,f,Min;
 47         while(dis[S]<=tot){
 48             if(p==T){
 49                 f=INF;
 50                 while(p!=S){
 51                     f=min(f,cap[path[p]]);
 52                     p=to[path[p]^1];
 53                 }ret+=f;p=T;
 54                 while(p!=S){
 55                     cap[path[p]]-=f;
 56                     cap[path[p]^1]+=f;
 57                     p=to[path[p]^1];
 58                 }
 59             }
 60             
 61             for(int &i=fron[p];i;i=nxt[i])
 62                 if(cap[i]&&dis[to[i]]==dis[p]-1)
 63                     {path[p=to[i]]=i;break;}
 64             
 65             if(!fron[p]){Min=tot;
 66                 if(--gap[dis[p]]==0)break;
 67                 for(int i=fir[p];i;i=nxt[i])
 68                     if(cap[i])Min=min(Min,dis[to[i]]);
 69                 gap[dis[p]=Min+1]+=1;fron[p]=fir[p];
 70                 if(p!=S)p=to[path[p]^1];    
 71             }        
 72         }
 73         return ret;
 74     }
 75 }ISAP;
 76 
 77 int a[maxn];
 78 int f[maxn];
 79 int main(){
 80     freopen("alis.in","r",stdin);
 81     freopen("alis.out","w",stdout);
 82     int n,S,T,ans=1;
 83     scanf("%d",&n);S=0;
 84     ISAP.Init(n+2);T=n+1;
 85     for(int i=1;i<=n;i++)
 86         scanf("%d",&a[i]);    
 87     
 88     for(int i=1;i<=n;i++){
 89         f[i]=1;
 90         for(int j=i-1;j>=1;j--)
 91             if(a[i]>=a[j])f[i]=max(f[i],f[j]+1);
 92         ans=max(f[i],ans);
 93     }
 94     printf("%d\n",ans);
 95     
 96     for(int i=1;i<=n;i++){
 97         if(f[i]==1)ISAP.addedge(S,i,1);
 98         if(f[i]==ans)ISAP.addedge(i,T,1);
 99         for(int j=i-1;j;j--)
100             if(f[j]==f[i]-1&&a[i]>=a[j])
101                 ISAP.addedge(j,i,1);
102     }
103     printf("%d\n",ISAP.Max_Flow(S,T));
104     ISAP.Init(n+2);S=0;T=n+1;
105     for(int i=1;i<=n;i++){
106         if(f[i]==1)ISAP.addedge(S,i,1);
107         if(f[i]==ans)ISAP.addedge(i,T,1);
108         for(int j=i-1;j;j--)
109             if(f[j]==f[i]-1&&a[i]>=a[j])
110                 ISAP.addedge(j,i,1);
111     }
112     ISAP.addedge(S,1,n);
113     if(f[n]==ans)ISAP.addedge(n,T,n);
114     printf("%d\n",ISAP.Max_Flow(S,T));
115     return 0;
116 }

 

[网络流24题] 试题库

★★   输入文件:testlib.in   输出文件:testlib.out   评测插件
时间限制:1 s   内存限制:128 MB

«问题描述:

 

假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取m 道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算法。

 

«编程任务:

 

对于给定的组卷要求,计算满足要求的组卷方案。

 

«数据输入:

 

由文件testlib.in提供输入数据。文件第1行有2个正整数k和n (2 <=k<= 20, k<=n<= 1000)k 表示题库中试题类型总数,n 表示题库中试题总数。第2 行有k 个正整数,第i 个正整数表示要选出的类型i 的题数。这k个数相加就是要选出的总题数m。接下来的n行给出了题库中每个试题的类型信息。每行的第1 个正整数p表明该题可以属于p类,接着的p个数是该题所属的类型号。

 

«结果输出:

 

程序运行结束时,将组卷方案输出到文件testlib.out 中。文件第i 行输出 “i:”后接类型i的题号。如果有多个满足要求的方案,只要输出1 个方案。如果问题无解,则输出“NoSolution!”。

 

输入文件示例

 

testlib.in

 

3 15

 

3 3 4

 

2 1 2

 

1 3

 

1 3

 

1 3

 

1 3

 

3 1 2 3

 

2 2 3

 

2 1 3

 

1 2

 

1 2

 

2 1 2

 

2 1 3

 

2 1 2

 

1 1

 

3 1 2 3

 

输出文件示例

testlib.out

1: 1 6 8

 

2: 7 9 10

 

3: 2 3 4 5

 

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <queue>
  5 using namespace std;
  6 const int maxn=100010;
  7 const int maxm=1000010;
  8 const int INF=1000000000;
  9 int n,k,cnt,fir[maxn],to[maxm],nxt[maxm],cap[maxm];
 10 int dis[maxn],gap[maxn],path[maxn],fron[maxn];
 11 queue<int>q;
 12 
 13 struct Net_Flow{
 14     int tot;
 15     void Init(int tot_){
 16         memset(dis,0,sizeof(dis));
 17         memset(gap,0,sizeof(gap));
 18         memset(fir,0,sizeof(fir));
 19         cnt=1;tot=tot_;
 20     }
 21     void add(int a,int b,int c){
 22         nxt[++cnt]=fir[a];
 23         cap[cnt]=c;
 24         fir[a]=cnt;
 25         to[cnt]=b;
 26     }
 27     void addedge(int a,int b,int c){
 28         add(a,b,c);add(b,a,0);
 29     }
 30     bool BFS(int S,int T){
 31         dis[T]=1;q.push(T);
 32         while(!q.empty()){
 33             int x=q.front();q.pop();
 34             for(int i=fir[x];i;i=nxt[i])
 35                 if(!dis[to[i]]){
 36                     dis[to[i]]=dis[x]+1;
 37                     q.push(to[i]);
 38                 }
 39         }
 40         return dis[S];
 41     }
 42     int Max_Flow(int S,int T){
 43         if(!BFS(S,T))return 0;
 44         for(int i=0;i<tot;i++)fron[i]=fir[i];
 45         for(int i=0;i<tot;i++)gap[dis[i]]+=1;
 46         int ret=0,p=S,f,Min;
 47         while(dis[S]<=tot){
 48             if(p==T){
 49                 f=INF;
 50                 while(p!=S){
 51                     f=min(f,cap[path[p]]);
 52                     p=to[path[p]^1];
 53                 }ret+=f;p=T;
 54                 while(p!=S){
 55                     cap[path[p]]-=f;
 56                     cap[path[p]^1]+=f;
 57                     p=to[path[p]^1];
 58                 }
 59             }
 60             
 61             for(int &i=fron[p];i;i=nxt[i])
 62                 if(cap[i]&&dis[to[i]]==dis[p]-1)
 63                     {path[p=to[i]]=i;break;}
 64             
 65             if(!fron[p]){Min=tot;
 66                 if(--gap[dis[p]]==0)break;
 67                 for(int i=fir[p];i;i=nxt[i])
 68                     if(cap[i])Min=min(Min,dis[to[i]]);
 69                 gap[dis[p]=Min+1]+=1;fron[p]=fir[p];
 70                 if(p!=S)p=to[path[p]^1];    
 71             }        
 72         }
 73         return ret;
 74     }
 75     void Solve(){
 76         for(int x=1;x<=k;x++){
 77             printf("%d: ",x);
 78             for(int i=fir[x];i;i=nxt[i])
 79                 if(to[i]>k&&!cap[i])
 80                     printf("%d ",to[i]-k);
 81             printf("\n");
 82         }
 83     }
 84 }ISAP;
 85 
 86 int main(){
 87     freopen("testlib.in","r",stdin);
 88     freopen("testlib.out","w",stdout);
 89     int S,T,ans,tot=0;
 90     scanf("%d%d",&k,&n);
 91     S=0;T=n+k+1;ISAP.Init(T+1);
 92     for(int i=1,v;i<=k;i++){
 93         scanf("%d",&v);tot+=v;
 94         ISAP.addedge(S,i,v);
 95     }
 96     for(int i=k+1,v,x;i<=k+n;i++){
 97         scanf("%d",&v);
 98         ISAP.addedge(i,T,v);
 99         while(v--){
100             scanf("%d",&x);
101             ISAP.addedge(x,i,1);
102         }
103     }
104     ans=ISAP.Max_Flow(S,T);
105     if(ans==tot)ISAP.Solve();
106     else puts("NoSolution!");
107     return 0;
108 }

[网络流24题] 机器人路径规划

★★★★   输入文件:robotpath.in   输出文件:robotpath.out   简单对比
时间限制:1 s   内存限制:128 MB
«问题描述:
机器人Rob可在一个树状路径上自由移动。给定树状路径T上的起点s 和终点t,机器
人Rob要从s运动到t。树状路径T上有若干可移动的障碍物。由于路径狭窄,任何时刻在
路径的任何位置不能同时容纳2 个物体。每一步可以将障碍物或机器人移到相邻的空顶点
上。设计一个有效算法用最少移动次数使机器人从s运动到t。
«编程任务:
对于给定的树T,以及障碍物在树T中的分布情况。计算机器人从起点s 到终点t的最
少移动次数。
«数据输入:
由文件robotpath.in提供输入数据。文件的第1 行有3 个正整数n,s和t,分别表示树T的
顶点数,起点s的编号和终点t 的编号。
接下来的n 行分别对应于树T 中编号为0,1,…,n-1 的顶点。每行的第1 个整数h
表示顶点的初始状态,当h=1 时表示该顶点为空顶点,当h=0 时表示该顶点为满顶点,其
中已有1 个障碍物。第2 个数k表示有k个顶点与该顶点相连。接下来的k个数是与该顶点
相连的顶点编号。
«结果输出:
程序运行结束时,将计算出的机器人最少移动次数输出到文件robotpath.out 中。如果无法
将机器人从起点移动到终点,输出“No solution!”。
输入文件示例 输出文件示例
robotpath.in
5 0 3
1 1 2
1 1 2
1 3 0 1 3
0 2 2 4

1 1 3

robotpath.out

3

  此题太难,有时间再补。

 

 

[网络流24题] 方格取数问题

★★☆   输入文件:grid.in   输出文件:grid.out   简单对比
时间限制:1 s   内存限制:128 MB

«问题描述:

 

在一个有m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任

 

意2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。

 

«编程任务:

 

对于给定的方格棋盘,按照取数要求编程找出总和最大的数。

 

«数据输入:

 

由文件grid.in提供输入数据。文件第1 行有2 个正整数m和n,分别表示棋盘的行数

 

和列数。接下来的m行,每行有n个正整数,表示棋盘方格中的数。

 

«结果输出:

 

程序运行结束时,将取数的最大总和输出到文件grid.out中。

 

输入文件示例 输出文件示例

 

grid.in

 

3 3

 

  1 2 3

 

3 2 3

 

2 3 1

 

grid.out

 

11

 


 

(1<=N,M<=30)

  之前已经写过。

[网络流24题] 餐巾

★★★   输入文件:napkin.in   输出文件:napkin.out   简单对比
时间限制:5 s   内存限制:128 MB

【问题描述】


 一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,…,N)。餐厅可以从三种途径获得餐巾。

    (1)购买新的餐巾,每块需p分;

    (2)把用过的餐巾送到快洗部,洗一块需m天,费用需f分(f<p)。如m=l时,第一天送到快洗部的餐巾第二天就可以使用了,送慢洗的情况也如此。

    (3)把餐巾送到慢洗部,洗一块需n天(n>m),费用需s分(s<f)。

    在每天结束时,餐厅必须决定多少块用过的餐巾送到快洗部,多少块送慢洗部。在每天开始时,餐厅必须决定是否购买新餐巾及多少,使洗好的和新购的餐巾之和满足当天的需求量Ri,并使N天总的费用最小。



【输入】

输入文件共 3 行,第 1 行为总天数;第 2 行为每天所需的餐巾块数;第 3 行为每块餐巾的新购费用 p ,快洗所需天数 m ,快洗所需费用 f ,慢洗所需天数 n ,慢洗所需费用 s 。

【输出】

一行,最小的费用

【样例】

napkin.in

3
3 2 4
10 1 6 2 3

napkin.out

64

【数据规模】

n<=200,Ri<=50

  之前已经写过。

 

[网络流24题] 软件补丁

★★   输入文件:bugs.in   输出文件:bugs.out   简单对比
时间限制:1 s   内存限制:128 MB

【问题描述】

对于一个软件公司来说,在发行一个新软件之后,可以说已经完成了工作。但是实际上,许多软件公司在发行一个新产品之后,还经常发送补丁程序,修改原产品中的错误(当然,有些补丁是要收费的)。
如某微硬公司就是这样的一个软件公司。今年夏天,在发行了一个新的字处理软件之后,到现在他们已经编写了许多补丁程序。仅仅在这个周末,他们就用新编写的 补丁程序解决了软件中的一个大问题。而在每一个补丁程序修改软件中的某些错误时,有可能引起软件中原来存在的某些错误重新发作。发生这种情况是因为当修改 一个错误时,补丁程序利用了程序中约定的特别行为,从而导致错误的重新产生。
微硬公司在他们的软件中一共发现了n个错误B={bl,b2,…,bn),现在他们一共发送了m 个补丁程序p1,p2,…,pm。如果想要在软件中应用第pi号补丁程序,则软件中必须存在错误B+i ≤B,并且错误B-i≤B必须不存在(显然,B+i∩B-i为空集)。然后,这个补丁程序将改正错误 F-i≤B(如果错误存在的话),并且产生新错误F+i≤B(同样,F+i∩F-i也为空集)。
现在,微硬公司的问题只有一个。他们给出一个原始版本的软件,软件包含了B中的所有错误,然后按照某一顺序在软件中应用补丁程序(应用某个补丁程序时,软 件必须符合该补丁程序的应用条件,且运行该程序需要一定的时间)。问怎样才能最快地改正软件中的所有错误(即为修正所有错误而运行的补丁程序的总时间最 短)?
 

【输入格式】

数据存放在当前目录下的文本文件“bugs.in"中。
文件的第一行包含两个整数n和m,分别表示软件中的错误个数和发送的补丁个数。其中,n和m满足条件:1≤n≤20,1≤m≤100。
接下来的m行(即第2行至第m+1行)按顺序描述了m个补丁程序的情况,第i行描述第i-1号补丁程序。每一行包含一个整数(表示在软件中应用该补丁程序所需的时间,单位为秒)和两个n个字符的字符串(中间均用一个空格分开)。、
第一个字符串描述了应用该补丁程序(第i-1号)的条件,即说明在软件中某错误应该存在还是不应该存在。字符串的第i个字符,如果是“+”,表示在软件中必须存在bi号错误;如果是“-”,表示软件中错误bi不能存在;如果是“0",则表示错误bi存在或不存在均可(即对应用该补丁程序没有影响)。
第二个字符串描述了应用该补丁程序(第i-1号)后的效果,即应用补丁程序后,哪些错误被修改好了,而又产生了哪些新错误。字符串的第i个字符,如果是“+”,表示产生了一个新错误bi;如果是“-”,表示错误bi被修改好了;如果是“0”,则表示错误bi不变(即原来存在,则仍然存在;原来不存在,则也不存在)。
 

【输出格式】

答案输出在当前目录下的文本文件“bugs.out"中。
请你找到一个应用补丁程序的最优顺序,修改软件中的所有错误,并且所用的时间最少。
注意,每个补丁程序是可以应用多次的。
如果存在这样一个序列,请在输出文件的第一行输出应用补丁程序的总时间(单位为秒);如果找不到这样一个序列,请在输出文件的第一行输出-1。
 

【输入输出样例】

样例输入(bugs.in):
3 3
1 000 00-
1 00- 0-+
2 0-- -++
样例输出(bugs.out):

  8

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <queue>
 5 #include <map>
 6 using namespace std;
 7 const int maxn=110;
 8 const int INF=1000000000;
 9 map<int,bool>vis;
10 map<int,int>dis;
11 int n,m,val[maxn];
12 char op[maxn][maxn];
13 char tp[maxn][maxn];
14 queue<int>q;
15 int main(){
16     freopen("bugs.in","r",stdin);
17     freopen("bugs.out","w",stdout);
18     scanf("%d%d",&n,&m);
19     for(int i=1;i<=m;i++){
20         scanf("%d",&val[i]);
21         scanf("%s",op[i]+1);
22         scanf("%s",tp[i]+1);
23     }
24     
25     q.push(0);vis[0]=1;
26     while(!q.empty()){
27         int x=q.front();
28         q.pop();vis[x]=0;
29         for(int t=1;t<=m;t++){
30             int f=1;
31             for(int i=1;i<=n;i++)
32                 if(!(x>>i-1&1)&&op[t][i]=='-'||x>>i-1&1&&op[t][i]=='+'){f=0;break;}
33                     
34             if(f==0)continue;
35             int y=x;
36             for(int i=1;i<=n;i++){
37                 if(tp[t][i]=='+')y&=((1<<n)-1)^(1<<(i-1));
38                 if(tp[t][i]=='-')y|=1<<(i-1);
39             }    
40             if(dis[y]==0&&y)dis[y]=INF;
41             if(dis[x]+val[t]<dis[y]){
42                 dis[y]=dis[x]+val[t];
43                 if(!vis[y]){
44                     q.push(y);
45                     vis[y]=1;
46                 }
47             }
48         }
49     }
50     if(dis[(1<<n)-1]!=0)
51         printf("%d\n",dis[(1<<n)-1]);
52     else printf("-1\n");    
53     return 0;
54 }

[CTSC1999][网络流24题] 星际转移

★★★☆   输入文件:home.in   输出文件:home.out   简单对比
时间限制:1 s   内存限制:128 MB

«问题描述:

由于人类对自然资源的消耗,人们意识到大约在2300 年之后,地球就不能再居住了。
于是在月球上建立了新的绿地,以便在需要时移民。令人意想不到的是,2177 年冬由于未
知的原因,地球环境发生了连锁崩溃,人类必须在最短的时间内迁往月球。现有n个太空站
位于地球与月球之间,且有m 艘公共交通太空船在其间来回穿梭。每个太空站可容纳无限
多的人,而每艘太空船i 只可容纳H[i]个人。每艘太空船将周期性地停靠一系列的太空站,
例如:(1,3,4)表示该太空船将周期性地停靠太空站134134134…。每一艘太空船从一个太
空站驶往任一太空站耗时均为1。人们只能在太空船停靠太空站(或月球、地球)时上、下船。
初始时所有人全在地球上,太空船全在初始站。试设计一个算法,找出让所有人尽快地全部
转移到月球上的运输方案。

«编程任务:

对于给定的太空船的信息,找到让所有人尽快地全部转移到月球上的运输方案。
«数据输入:
由文件home.in提供输入数据。文件第1行有3 个正整数n(太空站个数),m(太空船
个数)和k(需要运送的地球上的人的个数)。其中 1<=m<=13, 1<=n<=20, 1<=k<=50。
接下来的m行给出太空船的信息。第i+1 行说明太空船pi。第1 个数表示pi 可容纳的
人数Hpi;第2 个数表示pi 一个周期停靠的太空站个数r,1<=r<=n+2;随后r 个数是停靠
的太空站的编号(Si1,Si2,…,Sir),地球用0 表示,月球用-1 表示。时刻0 时,所有太空船都
在初始站,然后开始运行。在时刻1,2,3…等正点时刻各艘太空船停靠相应的太空站。人
只有在0,1,2…等正点时刻才能上下太空船。

«结果输出:

程序运行结束时,将全部人员安全转移所需的时间输出到文件home.out中。如果问题
无解,则输出0。

输入文件示例 输出文件示例

home.in
2 2 1
1 3 0 1 2

1 3 1 2 -1

home.out

5

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <queue>
  5 using namespace std;
  6 const int maxn=100010;
  7 const int maxm=1000010;
  8 const int INF=1000000000;
  9 int cnt,fir[maxn],to[maxm],nxt[maxm],cap[maxm];
 10 int dis[maxn],gap[maxn],path[maxn],fron[maxn];
 11 int room[110],rnd[110][110],N,M,K;;
 12 queue<int>q;
 13 struct Net_Flow{
 14     int tot;
 15     void Init(int tot_){
 16         memset(dis,0,sizeof(dis));
 17         memset(gap,0,sizeof(gap));
 18         memset(fir,0,sizeof(fir));
 19         cnt=1;tot=tot_;
 20     }
 21     void add(int a,int b,int c){
 22         nxt[++cnt]=fir[a];
 23         cap[cnt]=c;
 24         fir[a]=cnt;
 25         to[cnt]=b;
 26     }
 27     void addedge(int a,int b,int c){
 28         add(a,b,c);add(b,a,0);
 29     }
 30     bool BFS(int S,int T){
 31         dis[T]=1;q.push(T);
 32         while(!q.empty()){
 33             int x=q.front();q.pop();
 34             for(int i=fir[x];i;i=nxt[i])
 35                 if(!dis[to[i]]){
 36                     dis[to[i]]=dis[x]+1;
 37                     q.push(to[i]);
 38                 }
 39         }
 40         return dis[S];
 41     }
 42     int Max_Flow(int S,int T){
 43         if(!BFS(S,T))return 0;
 44         for(int i=0;i<tot;i++)fron[i]=fir[i];
 45         for(int i=0;i<tot;i++)gap[dis[i]]+=1;
 46         int ret=0,p=S,f,Min;
 47         while(dis[S]<=tot){
 48             if(p==T){
 49                 f=INF;
 50                 while(p!=S){
 51                     f=min(f,cap[path[p]]);
 52                     p=to[path[p]^1];
 53                 }ret+=f;p=T;
 54                 while(p!=S){
 55                     cap[path[p]]-=f;
 56                     cap[path[p]^1]+=f;
 57                     p=to[path[p]^1];
 58                 }
 59             }
 60             
 61             for(int &i=fron[p];i;i=nxt[i])
 62                 if(cap[i]&&dis[to[i]]==dis[p]-1)
 63                     {path[p=to[i]]=i;break;}
 64             
 65             if(!fron[p]){Min=tot;
 66                 if(--gap[dis[p]]==0)break;
 67                 for(int i=fir[p];i;i=nxt[i])
 68                     if(cap[i])Min=min(Min,dis[to[i]]);
 69                 gap[dis[p]=Min+1]+=1;fron[p]=fir[p];
 70                 if(p!=S)p=to[path[p]^1];    
 71             }        
 72         }
 73         return ret;
 74     }
 75     #define add1 ((t-1)*N)
 76     #define add2 ((t)*N)
 77     bool Check(int mid){
 78         Init((mid+1)*N+3);
 79         int ss=N*(mid+1)+1;
 80         int S=0,T=N*(mid+1)+2;
 81         addedge(S,ss,K);
 82         for(int i=1;i<=M;i++){
 83             for(int t=1,p;t<=mid;t++){
 84                 p=(t-1)%rnd[i][0]+1;
 85                 int u=rnd[i][p];
 86                 int v=rnd[i][p%rnd[i][0]+1];
 87                 if(u==-1||v==0)
 88                     continue;
 89                 if(u==0&&v==-1)
 90                     addedge(ss,T,room[i]);
 91                 else if(u==0)
 92                     addedge(ss,add2+v,room[i]);
 93                 else if(v==-1)
 94                     addedge(add1+u,T,room[i]);
 95                 else 
 96                     addedge(add1+u,add2+v,room[i]);    
 97             }
 98         }
 99         for(int t=3;t<=mid;t++)
100         for(int i=1;i<=N;i++)
101         addedge((t-2)*N+i,(t-1)*N+i,INF);    
102         return Max_Flow(S,T)>=K;
103     }
104     int Solve(){
105         int lo=1,hi=500;
106         while(lo<=hi){
107             int mid=(lo+hi)>>1;
108             if(Check(mid))hi=mid-1;
109             else lo=mid+1;
110         }
111         if(lo==501)lo=0;
112         return lo;
113     }
114 }ISAP;
115 
116 
117 
118 int main(){
119     freopen("home.in","r",stdin);
120     freopen("home.out","w",stdout);
121     scanf("%d%d%d",&N,&M,&K);
122     for(int i=1;i<=M;i++){
123         scanf("%d",&room[i]);
124         scanf("%d",&rnd[i][0]);
125         for(int j=1;j<=rnd[i][0];j++)
126             scanf("%d",&rnd[i][j]);    
127     }
128     printf("%d\n",ISAP.Solve());
129     return 0;
130 }

[网络流24题] 运输问题

★★   输入文件:tran.in   输出文件:tran.out   简单对比
时间限制:1 s   内存限制:128 MB
«问题描述:

«编程任务:
对于给定的m 个仓库和n 个零售商店间运送货物的费用,计算最优运输方案和最差运
输方案。
«数据输入:

«结果输出:
程序运行结束时,将计算出的最少运输费用和最多运输费用输出到文件tran.out中。
输入文件示例 输出文件示例
tran.in
2 3
220 280
170 120 210
77 39 105

150 186 122

tran.out

48500

69140


对于所有数据:1<=N,M<=100

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <queue>
 5 using namespace std;
 6 const int maxn=510;
 7 const int maxm=8010;
 8 const int INF=100000000;
 9 int cnt=1,fir[maxn],nxt[maxm];
10 int to[maxm],cap[maxm],val[maxm];
11 void addedge(int a,int b,int c,int v){
12     nxt[++cnt]=fir[a];to[cnt]=b;
13     cap[cnt]=c;val[cnt]=v;fir[a]=cnt;
14 }
15 
16 queue<int>q;
17 int path[maxn];
18 int dis[maxn],vis[maxn];
19 int Spfa(int S,int T){
20     for(int i=S+1;i<=T;i++)
21         dis[i]=INF;
22     q.push(S);vis[S]=1;
23     while(!q.empty()){
24         int x=q.front();
25         q.pop();vis[x]=0;
26         for(int i=fir[x];i;i=nxt[i])
27             if(cap[i]&&dis[to[i]]>dis[x]+val[i]){
28                 dis[to[i]]=dis[x]+val[i];
29                 if(!vis[to[i]])q.push(to[i]);
30                 vis[to[i]]=1;path[to[i]]=i;
31             }
32     }
33     return dis[T]==INF?0:dis[T];
34 }
35 
36 int Aug(int S,int T){
37     int f=INF,p=T;
38     while(p!=S){
39         f=min(f,cap[path[p]]);
40         p=to[path[p]^1];
41     }
42     p=T;
43     while(p!=S){
44         cap[path[p]]-=f;
45         cap[path[p]^1]+=f;
46         p=to[path[p]^1];
47     }
48     return f;
49 }
50 
51 int MCMF(int S,int T){
52     int ret=0,d;
53     while(d=Spfa(S,T))
54         ret+=Aug(S,T)*d;
55     return ret;
56 }
57 
58 int S,T;
59 int n,m;
60 int main(){
61     freopen("tran.in","r",stdin);
62     freopen("tran.out","w",stdout);
63     scanf("%d%d",&m,&n);S=0;T=n+m+1;
64     for(int i=1,x;i<=m;i++){
65         scanf("%d",&x);
66         addedge(S,i,x,0);
67         addedge(i,S,0,0);
68     }
69     
70     for(int i=m+1,x;i<=m+n;i++){
71         scanf("%d",&x);
72         addedge(i,T,x,0);
73         addedge(T,i,0,0);
74     }
75     
76     for(int i=1;i<=m;i++)
77         for(int j=m+1,x;j<=n+m;j++){
78             scanf("%d",&x);
79             addedge(i,j,INF,x);
80             addedge(j,i,0,-x);
81         }
82     printf("%d\n",MCMF(S,T));
83     for(int i=2;i<=cnt;i+=2){
84         val[i]*=-1;
85         val[i^1]*=-1;
86         cap[i]+=cap[i^1];
87         cap[i^1]=0;
88     }
89     printf("%d\n",-MCMF(S,T));    
90     return 0;
91 }

[网络流24题] 分配问题

★★   输入文件:job.in   输出文件:job.out   简单对比
时间限制:1 s   内存限制:128 MB

«问题描述:

有n件工作要分配给n个人做。第i 个人做第j 件工作产生的效益为ij c 。试设计一个将
n件工作分配给n个人做的分配方案,使产生的总效益最大。

«编程任务:

对于给定的n件工作和n个人,计算最优分配方案和最差分配方案。

«数据输入:

由文件job.in提供输入数据。文件的第1 行有1 个正整数n,表示有n件工作要分配
给n 个人做。接下来的n 行中,每行有n 个整数ij c ,1≤i≤n,1≤j≤n,表示第i 个人做
第j件工作产生的效益为ij c 。

«结果输出:

程序运行结束时,将计算出的最小总效益和最大总效益输出到文件job.out中。
输入文件示例 输出文件示例
job.in

5

2 2 2 1 2

2 3 1 2 4

2 0 1 1 1

2 3 4 3 3

3 2 1 2 1

job.out

5

14

数据范围

N<=100

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <queue>
 5 using namespace std;
 6 const int maxn=510;
 7 const int maxm=8010;
 8 const int INF=100000000;
 9 int cnt=1,fir[maxn],nxt[maxm];
10 int to[maxm],cap[maxm],val[maxm];
11 void addedge(int a,int b,int c,int v){
12     nxt[++cnt]=fir[a];to[cnt]=b;
13     cap[cnt]=c;val[cnt]=v;fir[a]=cnt;
14 }
15 
16 queue<int>q;
17 int path[maxn];
18 int dis[maxn],vis[maxn];
19 int Spfa(int S,int T){
20     for(int i=S+1;i<=T;i++)
21         dis[i]=INF;
22     q.push(S);vis[S]=1;
23     while(!q.empty()){
24         int x=q.front();
25         q.pop();vis[x]=0;
26         for(int i=fir[x];i;i=nxt[i])
27             if(cap[i]&&dis[to[i]]>dis[x]+val[i]){
28                 dis[to[i]]=dis[x]+val[i];
29                 if(!vis[to[i]])q.push(to[i]);
30                 vis[to[i]]=1;path[to[i]]=i;
31             }
32     }
33     return dis[T];
34 }
35 
36 int Aug(int S,int T){
37     int f=INF,p=T;
38     while(p!=S){
39         f=min(f,cap[path[p]]);
40         p=to[path[p]^1];
41     }
42     p=T;
43     while(p!=S){
44         cap[path[p]]-=f;
45         cap[path[p]^1]+=f;
46         p=to[path[p]^1];
47     }
48     return f;
49 }
50 
51 int MCMF(int S,int T){
52     int ret=0,d;
53     while((d=Spfa(S,T))!=INF)
54         ret+=Aug(S,T)*d;
55     return ret;
56 }
57 
58 int S,T;
59 int n;
60 int main(){
61     freopen("job.in","r",stdin);
62     freopen("job.out","w",stdout);
63     scanf("%d",&n);S=0;T=2*n+1;
64     for(int i=1;i<=n;i++){
65         addedge(S,i,1,0);
66         addedge(i,S,0,0);
67         addedge(i+n,T,1,0);
68         addedge(T,i+n,0,0);
69     }
70         
71     for(int i=1;i<=n;i++)
72         for(int j=n+1,x;j<=2*n;j++){
73             scanf("%d",&x);
74             addedge(i,j,1,x);
75             addedge(j,i,0,-x);
76         }
77     printf("%d\n",MCMF(S,T));
78     for(int i=2;i<=cnt;i+=2){
79         val[i]*=-1;
80         val[i^1]*=-1;
81         cap[i]+=cap[i^1];
82         cap[i^1]=0;
83     }
84     printf("%d\n",-MCMF(S,T));    
85     return 0;
86 }

 

[网络流24题] 负载平衡

★★   输入文件:overload.in   输出文件:overload.out   简单对比
时间限制:1 s   内存限制:128 MB

«问题描述:

 

G 公司有n 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等。如何用最

 

少搬运量可以使n 个仓库的库存数量相同。搬运货物时,只能在相邻的仓库之间搬运。

 

«编程任务:

 

对于给定的n 个环形排列的仓库的库存量,编程计算使n 个仓库的库存数量相同的最少

 

搬运量。

 

«数据输入:

 

由文件overload.in提供输入数据。文件的第1 行中有1 个正整数n(n<=100),表示有n

 

个仓库。第2 行中有n个正整数,表示n个仓库的库存量。

 

«结果输出:

 

程序运行结束时,将计算出的最少搬运量输出到文件overload.out中。

 

输入文件示例 输出文件示例

 

overload.in

 

5

 

17 9 14 16 4

overload.out

11
 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cmath>
 6 using namespace std;
 7 const int maxn=110;
 8 int a[maxn],b[maxn];
 9 int main(){
10     freopen("overload.in","r",stdin);
11     freopen("overload.out","w",stdout);
12     int n,tot=0;
13     scanf("%d",&n);
14     for(int i=1;i<=n;i++){
15         scanf("%d",&a[i]);
16         tot+=a[i];
17     }
18     tot/=n;
19     for(int i=1;i<n;i++){
20         b[i]=tot-a[i];
21         if(i>1)b[i]+=b[i-1];
22     }
23     sort(b+1,b+n+1);
24     int ans=0;
25     for(int i=1;i<=n;i++)
26         ans+=abs(b[(n+1)/2]-b[i]);
27         
28     printf("%d\n",ans);
29     return 0;
30 }

 

[网络流24题] 最长k可重线段集

[网络流24题] 最长k可重区间集

★★★   输入文件:interv.in   输出文件:interv.out   简单对比
时间限制:1 s   内存限制:128 MB
«问题描述:

«编程任务:
对于给定的开区间集合I和正整数k,计算开区间集合I的最长k可重区间集的长度。
«数据输入:
由文件interv.in提供输入数据。文件的第1 行有2 个正整数n和k,分别表示开区间的
个数和开区间的可重迭数。接下来的n行,每行有2个整数,表示开区间的左右端点坐标。
«结果输出:
程序运行结束时,将计算出的最长k可重区间集的长度输出到文件interv.out中。
输入文件示例 输出文件示例
interv.in
4 2
1 7
6 8
7 10

9 13

interv.out

15

 

  1 #include <algorithm> 
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdio>
  5 #include <queue>
  6 using namespace std;
  7 const int INF=233333333;
  8 const int maxn=2010,maxm=20010;
  9 int cnt,fir[maxn],nxt[maxm],to[maxm],cap[maxm],val[maxm],dis[maxn],path[maxn];
 10 struct data{
 11     int l,r,v;
 12     bool operator <(const data A)const{
 13         if(l!=A.l)
 14             return l<A.l;
 15         return r<A.r;     
 16     }
 17 }ar[maxn];
 18 
 19 struct data2{
 20     int a,pos;
 21     bool operator <(const data2 A)const{
 22         if(a!=A.a)
 23             return a<A.a;
 24         return pos<A.pos;     
 25     }
 26 }br[maxn];
 27 
 28 void addedge(int a,int b,int c,int v)
 29 {
 30     nxt[++cnt]=fir[a];to[cnt]=b;cap[cnt]=c;val[cnt]=v;fir[a]=cnt;
 31 }
 32 int S,T;
 33 int Spfa()
 34 {
 35     queue<int>q;
 36     memset(dis,-1,sizeof(dis));
 37     q.push(S);dis[S]=0;
 38     while(!q.empty())
 39     {
 40         int node=q.front();q.pop();
 41         for(int i=fir[node];i;i=nxt[i])
 42             if(cap[i]&&dis[node]+val[i]>dis[to[i]]){
 43                 dis[to[i]]=val[i]+dis[node];
 44                 path[to[i]]=i;
 45                 q.push(to[i]);
 46             }
 47     }
 48     return dis[T]==-1?0:dis[T]; 
 49 }
 50 
 51 int Aug()
 52 {
 53     int p=T,f=INF;
 54     while(p!=S)
 55     {
 56         f=min(f,cap[path[p]]);
 57         p=to[path[p]^1];
 58     }
 59     p=T;
 60     while(p!=S)
 61     {
 62         cap[path[p]]-=f;
 63         cap[path[p]^1]+=f;
 64         p=to[path[p]^1];
 65     }
 66     return f;
 67 }
 68 
 69 int MCMF()
 70 {
 71     int ret=0,d;
 72     while(d=Spfa())
 73         ret+=Aug()*d;
 74     return ret;    
 75 }
 76 
 77 int cont;
 78 void Init()
 79 {
 80     cnt=1;cont=0;
 81     memset(fir,0,sizeof(fir));
 82 }
 83 
 84 int main()
 85 {
 86     freopen("interv.in","r",stdin);
 87     freopen("interv.out","w",stdout);
 88     int n,k;
 89     {
 90         Init();
 91         scanf("%d%d",&n,&k);    
 92         for(int i=1;i<=n;i++){
 93             scanf("%d%d",&ar[i].l,&ar[i].r);
 94             ar[i].v=ar[i].r-ar[i].l;
 95         }
 96         sort(ar+1,ar+n+1);
 97         for(int i=1;i<=n;i++){
 98             br[i*2-1].a=ar[i].l;br[i*2].a=ar[i].r;
 99             br[i*2-1].pos=br[i*2].pos=i;
100         }
101         sort(br+1,br+2*n+1);
102         for(int i=1;i<=n;i++)
103             ar[i].l=ar[i].r=0;
104         for(int i=1;i<=2*n;i++)
105         {
106             int p=br[i].pos;
107             if(!ar[p].l){
108                 ar[p].l=++cont;
109             }
110             else{
111                 ar[p].r=++cont;
112             }
113         }
114 
115         S=0;T=cont+1;
116         for(int i=0;i<cont+1;i++)
117             addedge(i,i+1,k,0),addedge(i+1,i,0,0); 
118         for(int i=1;i<=n;i++)
119             addedge(ar[i].l,ar[i].r,1,ar[i].v),addedge(ar[i].r,ar[i].l,0,-ar[i].v);
120         printf("%d\n",MCMF());        
121     }
122     return 0;
123 }

 

posted @ 2016-07-20 16:10  TenderRun  阅读(270)  评论(0编辑  收藏  举报