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

网络流24题

时间:2015-07-29 21:10:56      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:

    

    网络流基本知识就不在这里阐述了

    算法实现题 8-1 飞行员配对方案问题



  问题描述:
      第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出
    的每一架飞机都需要配备在航行技能和语言上能互相配合的 2 名飞行员, 其中 1 名是英国飞
    行员,另 1 名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英
    国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的
    外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空
    军一次能派出最多的飞机。
  编程任务:
      对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,
    使皇家空军一次能派出最多的飞机。
  数据输入:
      由文件 input.txt 提供输入数据。文件第 1 行有 2 个正整数 m 和 n。n 是皇家空军的飞行
    员总数(n<100);m 是外籍飞行员数。外籍飞行员编号为 1~m;英国飞行员编号为 m+1~n。
    接下来每行有 2 个正整数 i 和 j,表示外籍飞行员 i 可以和英国飞行员 j 配合。文件最后以 2
    个-1 结束。
  结果输出:
      程序运行结束时,将最佳飞行员配对方案输出到文件 output.txt 中。第 1 行是最佳飞行
    员配对方案一次能派出的最多的飞机数 M。接下来 M 行是最佳飞行员配对方案。每行有 2
    个正整数 i 和 j,表示在最佳飞行员配对方案中,飞行员 i 和飞行员 j 配对。
    如果所求的最佳飞行员配对方案不存在,则输出‘No Solution!’ 。


  我们先画个图~技术分享

  我们发现这题就是求二分图的最大匹配?

  好吧,你有两个选择 

  1.敲KM

  2.外籍飞行员放在x集合里面,英国王牌飞行员放在y集合里面,设立源点S,汇点T,S向每个x集合里面的点连一条容量为1的边(限制每个点只能连出一条边),y集合里面每个点连一条容量为1的点到T,每个配对连容量为1的边,跑最大流。

  网络流第一个建模。。还体验了一把输出方案的可怕之处。(从此立下没有SPJ || 唯一解 不打方案的flag!)

技术分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<queue>
 6 
 7 #define maxn 102
 8 
 9 using namespace std;
10 
11 int dis[maxn],dp[maxn][maxn],m;
12 
13 bool DFS()
14 {
15     memset(dis,-1,sizeof(dis));
16     dis[0]=1;
17     queue<int>q;
18     q.push(0);
19     while(!q.empty())
20     {
21         int u=q.front();
22         if(u==m+1)break;
23         q.pop();
24         for(int i=0;i<=m+1;i++)if(dis[i]==-1&&dp[u][i]>0){
25             dis[i]=dis[u]+1;
26             q.push(i);
27         }
28     }
29     if(dis[m]==-1)return 0;
30     else return 1;
31 }
32 
33 int find(int poi,int low)
34 {
35     int a;
36     if(poi==m+1)return low;
37     for(int i=0;i<=m+1;i++)if(dp[poi][i]>0&&dis[i]==dis[poi]+1){
38         a=find(i,min(low,dp[poi][i]));
39         if(a){
40             dp[poi][i]-=a;
41             dp[i][poi]+=a;
42             return a;
43         }
44     }
45     return 0;
46 }
47 
48 int main()
49 {
50     int a,n,x,y,ans=0;
51     scanf("%d%d%d%d",&n,&m,&x,&y);
52     while(x!=-1&&y!=-1)
53     {
54         dp[x][y]=1;
55         scanf("%d%d",&x,&y);
56     }
57     for(int i=1;i<=n;i++)
58         dp[0][i]=1;
59     for(int i=n+1;i<=m;i++)
60         dp[i][m+1]=1;
61     while(DFS())
62     {    
63         a=find(0,99999999);
64         while(a)
65         {
66             ans+=a;
67             a=find(0,99999999);
68         }
69     }
70     printf("%d",ans);
71     return 0;
72 }
View Code

 


    算法实现题 8-2 太空飞行计划问题


  问题描述:
       W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业
    性实验而获取利润。现已确定了一个可供选择的实验集合 E={E1,E2,…,Em},和进行这
    些实验需要使用的全部仪器的集合 I={I1, I2,…In}。 实验 Ej需要用到的仪器是 I 的子集 RjÍI。
    配置仪器 Ik的费用为 ck美元。实验 Ej的赞助商已同意为该实验结果支付 pj美元。W 教授的
    任务是找出一个有效算法, 确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才
    能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部
    费用的差额。
  编程任务:
      对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
  数据输入:
      由文件 input.txt 提供输入数据。文件第 1 行有 2 个正整数 m 和 n。m 是实验数,n 是仪
    器数。接下来的 m 行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费
    用;接着是该实验需要用到的若干仪器的编号。最后一行的 n 个数是配置每个仪器的费用。
  结果输出:
      程序运行结束时,将最佳实验方案输出到文件 output.txt 中。第 1 行是实验编号;第 2
    行是仪器编号;最后一行是净收益。


    一道最小割的好题!求最小割==求最大流。。或者用某专门求最小割的算法

    关于一些证明:http://www.cnblogs.com/wuyiqi/archive/2012/03/12/2391960.html

    我不信邪再输了一次方案。下面是代码。结果呵呵了。flag继续立起来!

 

技术分享
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<vector>
  6 #include<queue>
  7 
  8 #define maxn 121
  9 
 10 using namespace std;
 11 
 12 vector <int> graph[maxn];
 13 vector <int> cgraph[maxn];
 14 vector <int> opp[maxn];
 15 
 16 int n,m,dis[maxn];
 17 
 18 bool g[maxn];
 19 
 20 bool DFS()
 21 {
 22     memset(dis,-1,sizeof(dis));
 23     queue<int>q;
 24     dis[0]=1;
 25     for(int i=0;i<graph[0].size();i++)if(cgraph[0][i]>0){
 26         int v=graph[0][i];
 27         dis[v]=2;
 28         q.push(v);
 29     }
 30     while(!q.empty())
 31     {
 32         int u=q.front();
 33         q.pop();
 34         for(int i=0;i<graph[u].size();i++)
 35             if(cgraph[u][i]>0&&dis[graph[u][i]]==-1)
 36             {
 37                 dis[graph[u][i]]=dis[u]+1;
 38                 q.push(graph[u][i]);
 39                 if(graph[u][i]==n+1+m)return 1;
 40             }
 41     }
 42     return 0;
 43 }
 44 
 45 int find(int poi,int low)
 46 {
 47     if(poi==n+m+1)return low;
 48     for(int i=0;i<graph[poi].size();i++)if(cgraph[poi][i]>0&&dis[graph[poi][i]]==dis[poi]+1){
 49         int a=find(graph[poi][i],min(low,cgraph[poi][i]));
 50         if(a)
 51         {
 52             cgraph[poi][i]-=a;
 53             int v=opp[poi][i];
 54             cgraph[graph[poi][i]][v]+=a;
 55             return a;
 56         }
 57     }
 58     return 0;
 59 }
 60 
 61 void addedge(int a,int b,int c)
 62 {
 63     graph[a].push_back(b);
 64     cgraph[a].push_back(c);
 65     opp[b].push_back(graph[a].size()-1);
 66     graph[b].push_back(a);
 67     cgraph[b].push_back(0);
 68     opp[a].push_back(graph[b].size()-1);
 69 }
 70 
 71 void luangao(int poi)
 72 {
 73     for(int i=0;i<graph[poi].size();i++)
 74     {
 75         int flag=0;
 76         if(cgraph[poi][i]>0)continue;
 77         for(int j=0;j<graph[graph[poi][i]].size();j++)
 78             for(int k=0;k<graph[graph[graph[poi][i]][j]].size();k++)
 79                 if(graph[graph[graph[poi][i]][j]][k]==m+n+1&&cgraph[graph[graph[poi][i]][j]][k]!=0)flag=1;
 80         if(flag==0){g[graph[poi][i]]=1;for(int j=0;j<graph[graph[poi][i]].size();j++)g[graph[graph[poi][i]][j]]=1;}
 81     }
 82 }
 83 
 84 void dfs(int poi)
 85 {
 86     for(int i=0;i<graph[poi].size();i++)if(cgraph[poi][i]>0&&!g[graph[poi][i]]){
 87         g[graph[poi][i]]=1;
 88         dfs(graph[poi][i]);
 89     }
 90 }
 91 
 92 int main()
 93 {
 94     freopen("shut.in","r",stdin);
 95        freopen("shut.out","w",stdout);
 96     int x=1,ans=0,sum=0;
 97     char s;
 98     scanf("%d%d",&n,&m);
 99     for(int i=1;i<=n;i++)
100     {
101         scanf("%d ",&x);ans+=x;
102         addedge(0,i,x);
103         int ss=0;
104         while(1)
105         {
106             scanf("%c",&s);
107             if(s==\n){
108                 if(ss)addedge(i,ss+n,99999999);
109                 break;
110             }
111             else if(s== )addedge(i,n+ss,99999999),ss=0;
112             else ss=ss*10+s-0;
113         }
114     }
115     for(int i=1;i<=m;i++)
116         scanf("%d",&x),addedge(i+n,n+m+1,x);
117      int a;
118     while(DFS())
119     {
120          while(a=find(0,99999999))
121             sum+=a;
122     }
123     dfs(0);
124 //    luangao(0);
125     for(int i=1;i<=n;i++)
126         if(g[i]==1)printf("%d ",i);
127     printf("\n");
128     for(int i=1;i<=m;i++)
129         if(g[i+n]==1)printf("%d ",i);
130     printf("\n%d",ans-sum);
131     return 0;
132 }
View Code 

 

    算法实现题 8-3 最小路径覆盖问题


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

    编程任务:
      对于给定的给定有向无环图 G,编程找出 G 的一个最小路径覆盖.
   数据输入:
      由文件 input.txt 提供输入数据。文件第 1 行有 2 个正整数 n 和 m。n 是给定有向无环图
    G 的顶点数, m 是 G 的边数。接下来的 m 行,每行有 2 个正整数 i 和 j,表示一条有向边(i,j)
    结果输出:
      程序运行结束时,将最小路径覆盖输出到文件 output.txt 中。从第 1 行开始,每行输出
    一条路径。文件的最后一行是最少路径数。

 


 

    首先我们知道选择的边数越多,路径就越少。

    所以我们只需把每个点拆成两个,放入x,y集合里面,然后按8-1的方法连边,跑最大流,用点数-最大流即可。

    这题又要输方案- -但是我拒绝!

    技术分享View Code


 

    算法实现题 8-4 最小路径覆盖问题

 



  问题描述:
      假设有 n 根柱子,现要按下述规则在这 n 根柱子中依次放入编号为 1,2,3,。。的球。
    (1)每次只能在某根柱子的最上面放球。
    (2)在同一根柱子中,任何 2 个相邻球的编号之和为完全平方数。
    试设计一个算法,计算出在 n 根柱子上最多能放多少个球。例如,在 4 根柱子上最多可
    放 11 个球。
  编程任务:
      对于给定的 n,计算在 n 根柱子上最多能放多少个球。
  数据输入:
      由文件 input.txt 提供输入数据。文件第 1 行有 1 个正整数 n,表示柱子数。
  结果输出:
      程序运行结束时,将 n 根柱子上最多能放的球数以及相应的放置方案输出到文件
    output.txt 中。文件的第一行是球数。接下来的 n 行,每行是一根柱子上的球的编号。


 

    首先直接出答案是不行的啦。。(听说有通项公式 - -)

    于是我们枚举答案,然后把能放在相邻的连一条边做最小路径覆盖然后看ans,ans大于答案就输出,否则继续,另外每次不需要额外建图,直接残量网络上加边继续跑就是的啦。。

    拒绝方案!

技术分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<vector>
 6 #include<queue>
 7 
 8 #define maxn 3202
 9 
10 using namespace std;
11 
12 vector <int> graph[maxn];
13 vector <int> fgraph[maxn];
14 vector <int> cgraph[maxn];
15 
16 int pf[61],dis[3202];
17 
18 void addedge(int a,int b,int c)
19 {
20     graph[a].push_back(b);
21     cgraph[a].push_back(c);
22     fgraph[b].push_back(graph[a].size()-1);
23     graph[b].push_back(a);
24     cgraph[b].push_back(0);
25     fgraph[a].push_back(graph[b].size()-1);
26 }
27 
28 void prework(int k)
29 {
30     addedge(0,k,1);
31     addedge(k+1600,3201,1);
32     for(int i=sqrt(k)+1;pf[i]-k<k;i++)
33         addedge(pf[i]-k,k+1600,99999999);
34 }
35 
36 bool DFS()
37 {
38     memset(dis,-1,sizeof(dis));
39     dis[0]=1;
40     queue<int>q;
41     for(int i=0;i<graph[0].size();i++)if(cgraph[0][i]>0&&dis[graph[0][i]]==-1){
42         dis[graph[0][i]]=2;
43         q.push(graph[0][i]);
44     }
45     while(!q.empty())
46     {
47         int u=q.front();
48         q.pop();
49         for(int i=0;i<graph[u].size();i++)
50         {
51     //        printf("%d %d",graph[u][i],cgraph[u][i]);
52             if(cgraph[u][i]>0&&dis[graph[u][i]]==-1){
53                 dis[graph[u][i]]=dis[u]+1;
54                 q.push(graph[u][i]);
55                 if(graph[u][i]==3201)return 1;
56             }
57         }
58     }
59     return 0;
60 }
61 
62 int find(int poi,int low)
63 {
64     if(poi==maxn-1)return low;
65     for(int i=0;i<graph[poi].size();i++)if(cgraph[poi][i]>0&&dis[graph[poi][i]]==dis[poi]+1){
66         int a=find(graph[poi][i],min(low,cgraph[poi][i]));
67         if(a){
68             cgraph[poi][i]-=a;
69             cgraph[graph[poi][i]][fgraph[poi][i]]+=a;
70             return a;
71         }
72     }
73     return 0;
74 }
75 
76 int main()
77 {
78     freopen("ball.in","r",stdin);
79     freopen("ball.out","w",stdout);
80     int n;
81     for(int i=1;i<=60;i++)pf[i]=i*i;
82     scanf("%d",&n);
83     int sum=0,a;
84     for(int i=1;;i++)
85     {
86         prework(i);
87         while(DFS()){while(a=find(0,99999999))sum+=a;}
88         if(i-sum>n){printf("%d",i-1);return 0;}
89     }
90 }
View Code 

    算法实现题 8-5 圆桌问题


 

    问题描述:
      假设有来自 n 个不同单位的代表参加一次国际会议。每个单位的代表数分别为
    ri,i , = 1,2,.., 。会议餐厅共有 m 张餐桌,每张餐桌可容纳ci (i = 1,2,.., m) 个代表就餐。
    为了使代表们充分交流, 希望从同一个单位来的代表不在同一个餐桌就餐。 试设计一个算法,
    给出满足要求的代表就餐方案。
    编程任务:
      对于给定的代表数和餐桌数以及餐桌容量,编程计算满足要求的代表就餐方案。
   数据输入:
      由文件 input.txt 提供输入数据。文件第 1 行有 2 个正整数 m 和 n,m 表示单位数,n 表
    示餐桌数,1<=m<=150, 1<=n<=270。文件第 2 行有 m 个正整数,分别表示每个单位的代表
    数。文件第 3 行有 n 个正整数,分别表示每个餐桌的容量。
      结果输出:
      程序运行结束时,将代表就餐方案输出到文件 output.txt 中。如果问题有解,在文件第
    1 行输出 1,否则输出 0。接下来的 m 行给出每个单位代表的就餐桌号。如果有多个满足要
    求的方案,只要输出 1 个方案。


    一眼看出桌子在左边,单位在右边,源点连桌子容量,汇点连代表数,每个桌子连容量为1的边,跑最大流。

    技术分享View Code

    看起来方案很好搞,结果。。呵呵。。


·    算法实现题 8-6 圆桌问题


 

    问题描述:
      给定正整数序列x1,.. xn 
    (1)计算其最长递增子序列的长度 s。
    (2)计算从给定的序列中最多可取出多少个长度为 s 的递增子序列。
    (3)如果允许在取出的序列中多次使用 x1和 xn,则从给定序列中最多可取出多少个长
    度为 s 的递增子序列。
     编程任务:
      设计有效算法完成(1)(2)(3)提出的计算任务。
    数据输入:
      由文件 input.txt 提供输入数据。文件第 1 行有 1 个正整数 n,表示给定序列的长度。接
    下来的 1 行有 n 个正整数.
      结果输出:
      程序运行结束时,将任务(1)(2)(3)的解答输出到文件 output.txt 中。第 1 行是最长
    递增子序列的长度 s。第 2 行是可取出的长度为 s 的递增子序列个数。第 3 行是允许在取出
    的序列中多次使用 x1和 xn时可取出的长度为 s 的递增子序列个数。

 


 

    第一问先DP艹过。。

    然后我们就可以开始建模啦!

    1、把序列每位i拆成两个点<i.a>和<i.b>,从<i.a>到<i.b>连接一条容量为1的有向边。
    2、建立附加源S和汇T,如果序列第i位有F[i]=K,从S到<i.a>连接一条容量为1的有向边。
    3、如果F[i]=1,从<i.b>到T连接一条容量为1的有向边。
    4、如果j>i且A[i] < A[j]且F[j]+1=F[i],从<i.b>到<j.a>连接一条容量为1的有向边。

    第二问跑最大流,第三问把边(<1.a>,<1.b>)(<N.a>,<N.b>)(S,<1.a>)(<N.b>,T)这四条边的容量修改为无穷大,再求一次网络最大流,就是第三问结果。  

技术分享
  1     #include<cstdio>
  2     #include<cstring>
  3     #include<queue>
  4     #include<cmath>
  5     #include<algorithm>
  6     
  7     #define maxn 501
  8     
  9     using namespace std;
 10     
 11     int o[maxn],num[maxn],b=0,dis[maxn*2],n;
 12     
 13     vector<int>graph[maxn*2];
 14     vector<int>cgraph[maxn*2];
 15     vector<int>fgraph[maxn*2];
 16     
 17     void addedge(int a,int b,int c)
 18     {
 19         graph[a].push_back(b);
 20         cgraph[a].push_back(c);
 21         fgraph[b].push_back(graph[a].size()-1);
 22         graph[b].push_back(b);
 23         cgraph[b].push_back(0);
 24         fgraph[a].push_back(graph[b].size()-1);
 25     }
 26     
 27     void clear(int kk){
 28         vector <int> neww;
 29         vector <int> new1;
 30         vector <int> new2;
 31         swap(neww,graph[kk]);
 32         swap(new1,cgraph[kk]);
 33         swap(new2,fgraph[kk]);
 34     }
 35     
 36     bool DFS()
 37     {
 38         memset(dis,-1,sizeof(dis));
 39         dis[0]=1;queue<int>q;
 40         q.push(0);
 41         while(!q.empty())
 42         {
 43             int u=q.front();
 44             q.pop();
 45             for(int i=0;i<graph[u].size();i++)if(cgraph[u][i]>0&&dis[graph[u][i]]==-1){
 46                 dis[graph[u][i]]=dis[u]+1;
 47                 q.push(graph[u][i]);
 48                 if(graph[u][i]==n*2+1)return true;
 49             }
 50         }
 51         return false;
 52     }
 53     
 54     int find(int poi,int low)
 55     {
 56         if(poi==2*n+1)return low;
 57         for(int i=0;i<graph[poi].size();i++)if(cgraph[poi][i]>0&&dis[graph[poi][i]]==dis[poi]+1){
 58             int a=find(graph[poi][i],min(cgraph[poi][i],low));
 59             if(a)
 60             {
 61                 cgraph[poi][i]-=a;
 62                 cgraph[graph[poi][i]][fgraph[poi][i]]+=a;
 63                 return a;
 64             }
 65         }
 66         return 0;
 67     }
 68     
 69     int main()
 70     {
 71         freopen("alis.in","r",stdin);
 72         freopen("alis.out","w",stdout);
 73         scanf("%d",&n);
 74         for(int i=1;i<=n;i++)
 75             scanf("%d",&o[i]);
 76         for(int i=1;i<=n;i++)
 77         {
 78             int kk=0; 
 79             for(int j=i-1;j>=1;j--)if(o[j]<=o[i]){
 80                 if(!kk)kk=j;
 81                 else if(num[kk]<num[j])kk=j;
 82             }
 83             if(!kk)num[i]=1;
 84             else num[i]=num[kk]+1;
 85         }
 86         int maxx=0;
 87         for(int i=1;i<=n;i++)
 88             maxx=max(maxx,num[i]);
 89         printf("%d\n",maxx);
 90         for(int i=1;i<=n;i++)
 91         {
 92             addedge(i,i+n,1);
 93             if(num[i]==1)addedge(i+n,n*2+1,1);
 94             if(num[i]==maxx)addedge(0,i,1);
 95         }
 96         for(int i=1;i<=n;i++)
 97             for(int j=i+1;j<=n;j++)
 98                 if(o[j]>=o[i]&&num[j]==num[i]+1)addedge(j+n,i,1);
 99         int a,sum=0;
100         while(DFS())while(a=find(0,99999999))sum+=a;
101         printf("%d\n",sum);
102         for(int i=0;i<=2*n+1;i++)clear(i);
103         for(int i=1;i<=n;i++)
104         {
105             if(i==n){
106                 addedge(i,i+n,99999999);
107                 if(num[n]==maxx)addedge(0,i,99999999);
108             }
109             if(i==1){
110                 addedge(i,i+n,99999999);
111                 addedge(i+n,n*2+1,99999999);
112             }
113             addedge(i,i+n,1);
114             if(num[i]==1)addedge(i+n,n*2+1,1);
115             if(num[i]==maxx)addedge(0,i,1);
116         }
117         for(int i=1;i<=n;i++)
118             for(int j=i+1;j<=n;j++)
119                 if(o[j]>=o[i]&&num[j]==num[i]+1)addedge(j+n,i,1);
120         sum=0;
121         while(DFS())while(a=find(0,99999999))sum+=a;
122         printf("%d",sum);
123         return 0;
124     }
View Code

 


    

 

网络流24题

标签:

原文地址:http://www.cnblogs.com/tuigou/p/4687177.html

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