2016.2.21
01 飞行员配对方案问题(习题 8-10)
每一条边连接外籍-国内飞行员,显然是一个二分图,最多出发的飞机数,对应着最多的边匹配。
问题转化为经典的二分图匹配问题,可以用匈牙利或者网络流。
源点和每一个外籍飞行员、每一个国内飞行员和汇点、每个可行的配合之间连接一条容量为1的有向边。
可以派出的最多飞机数就是这个网络的最大流
建图部分代码
1 for(;;){ 2 int a,b,c; 3 a=read();b=read(); 4 if(a==-1&&b==-1) break; 5 insert(a,b,1); 6 } 7 for(int i=1;i<=m;i++) insert(n+1,i,1); 8 for(int i=m+1;i<=n;i++) insert(i,n+2,1);
对于方案。。其实我们可以在增广的时候做标记的,但是反正比较懒套个模板嘛~
在时候枚举一下飞行员之间边,如果他的容量被修改为0了。那么这就是一对一对
1 for(int i=1;i<=m;i++){ 2 for(int j=last[i];j;j=e[j].next){ 3 if(e[j].cap==0&&e[j].to<=n&&e[j].to>=1){ 4 printf("%d %d\n",i,e[j].to); 5 break; 6 } 7 } 8 }//2016.2.21
02 太空飞行计划问题
大概想了一下,连接实验和所需的实验器材,容量是inf,连接源点和每个实验,容量是实验经费,连接器材和汇点,容量是器材费用
然后算算好像答案是这个网络的最小割?写个最小割就好了
考虑对于每个实验,如果这个子图的割在器材-汇之间,说明他是赚钱的,否则是赔钱的(好像不太对?想不出证明) 2016.2.21
2016.2.22 答案是所有赞助商给的经费-最小割
懒得处理输入了,假装每行有一个0做结束标志。
1 scanf("%d %d",&m,&n); 2 for(int i=1;i<=m;i++){ 3 scanf("%d",&p[i]); 4 int a;sum+=p[i];
5 while(scanf("%d",&a),a)
6 insert(i,a+m,inf);
7 } 8 for(int i=1;i<=n;i++) {scanf("%d",&c[i]);} 9 s=n+m+1;t=n+m+2; 10 for(int i=1;i<=m;i++) insert(s,i,p[i]); 11 for(int i=1;i<=n;i++) insert(m+i,t,c[i]); 12 int tp=dinic(s,t); 13 printf("%d",sum-tp);
*净收入=赞助费-成本 细思恐极
2016.2.29 还要输出方案。。把实验和仪器分开,不和t联通的实验被选中,器材同理。
2333我突然想起来dinic的bfs可以判联通移动
1 int tp=dinic(s,t); 2 for(int i=1;i<=m;i++){ 3 if(!bfs(i,t)){ 4 printf("%d ",i); 5 } 6 } putchar('\n'); 7 for(int i=1;i<=n;i++){ 8 if(!bfs(m+i,t)){ 9 printf("%d ",i); 10 } 11 } 12 printf("\n%d",sum-tp);
03 最小路径覆盖问题
我一看题目,诶 最小生成树?哎哟有向图
诶我靠可以写最小生成树
诶不对看错题目了
那么我们设 V={1,2,3... n},构造网络 G1=(V1,E1)如下:
V1 = {x0 , x1,, xn}∪{y0 , y1,, yn},
E1 = {(x0 , xi )} ∪{( yi , y0 )}∪{(xi , yj )} (i. j)∈ E}
每条边容量都是1,求x0 y0的最大流
G1最大流也就是他的最大匹配数
最小路径覆盖=总节点数-最大匹配数 我们可以轻易的解决这个问题
1 s=n+n+1;t=n+n+2; 2 for(int i=1;i<=n;i++){ 3 insert(s,i,1); 4 insert(n+i,t,1); 5 } 6 for(int i=1;i<=m;i++){ 7 insert(edge[i][1],edge[i][2]+n,1); 8 } 9 printf("%d",n-dinic(s,t));
2016.2.22输出路径,这个就有点意思了,不会
2016.2.29还是不会
2016.3.2大概懂了,我们在每一次增广的时候,纪录一个to[x]..就是我们所谓的路径覆盖,在结束dinic之后,输出路径覆盖的集合就好了
1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 const int inf=0x7fffffff; 8 struct edge{ 9 int to,cap,next; 10 }e[30000]; 11 int h[405],mark[405],to[405]; 12 int n,m,s,t; 13 int last[405],iter[405],ecnt=1; 14 void insert(int from,int to,int cap){ 15 e[++ecnt]=(edge){to,cap,last[from]};last[from]=ecnt; 16 e[++ecnt]=(edge){from,0,last[to]};last[to]=ecnt; 17 } 18 bool bfs(int s,int t){ 19 memset(h,-1,sizeof(h)); 20 queue<int>q; 21 q.push(s);h[s]=0; 22 while(!q.empty()){ 23 int c=q.front();q.pop(); 24 for(int u=last[c];u;u=e[u].next){ 25 if(e[u].cap>0&&h[e[u].to]==-1){ 26 h[e[u].to]=h[c]+1; 27 q.push(e[u].to); 28 } 29 } 30 } 31 return h[t]!=-1; 32 } 33 int dfs(int x,int t,int f){ 34 if(x==t) return f; 35 int w,used=0; 36 for(int u=iter[x];u;u=e[u].next){ 37 if(h[e[u].to]==h[x]+1){ 38 w=dfs(e[u].to,t,min(f-used,e[u].cap)); 39 if(w){ 40 to[x]=e[u].to; 41 if(e[u].to-n>0) 42 mark[e[u].to-n]=1; 43 } 44 e[u].cap-=w; 45 e[u^1].cap+=w; 46 if(e[u].cap) iter[x]=u; 47 used+=w; 48 if(used==f) return f; 49 } 50 } 51 if(!used)h[x]=-1; 52 return used; 53 } 54 int dinic(int s,int t){ 55 int flow=0; 56 while(bfs(s,t)){ 57 for(int i=0;i<=t;i++) iter[i]=last[i]; 58 flow+=dfs(s,t,inf); 59 } 60 return flow; 61 } 62 int edge[6005][2]; 63 int main(){ 64 scanf("%d %d",&n,&m); 65 for(int i=1;i<=m;i++){ 66 scanf("%d %d",&edge[i][1],&edge[i][2]); 67 } 68 s=0;t=n+n+1; 69 for(int i=1;i<=n;i++){ 70 insert(s,i,1); 71 insert(n+i,t,1); 72 } 73 74 for(int i=1;i<=m;i++){ 75 insert(edge[i][1],edge[i][2]+n,1); 76 } 77 int H=dinic(s,t); 78 for(int i=1;i<=n;i++){ 79 if(mark[i])continue; 80 printf("%d",i); 81 int k=i; 82 while(to[k]) 83 { 84 printf(" %d",to[k]-n); 85 k=to[k]-n; 86 } 87 printf("\n"); 88 } 89 printf("%d",n-H); 90 }
04 魔术球问题
3.2 一看就是打表啊