【网络流24题】 No.2 太空飞行计划问题 (最大闭合权图 最大流 )

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

output
1 2
1 2 3
17

 
 
【分析】
  就是一个裸的最大权闭合子图啦。
  但是输出方案让我很内伤。。。
  上一题是点数尽量少,这一题是尽量多。。。
  就是一些又不赚钱又不赔钱的也要算上。 
  但是跑最大流的话,会把他割掉,然后dfs方法就不行了,内伤、、、
  纠结了好久
  网上有人说那就枚举把。。。
 
  但是,我转念一想,不如猥琐一遍,,,然后我就放大边权,,,过了!!!!
 
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 110
  9 #define INF 0xfffffff
 10 
 11 struct node
 12 {
 13     int x,y,f,o,next;
 14 }t[Maxn*Maxn];int len;
 15 int first[Maxn];
 16 
 17 int mymin(int x,int y) {return x<y?x:y;}
 18 
 19 void ins(int x,int y,int f)
 20 {
 21     t[++len].x=x;t[len].y=y;t[len].f=f;
 22     t[len].next=first[x];first[x]=len;t[len].o=len+1;
 23     t[++len].x=y;t[len].y=x;t[len].f=0;
 24     t[len].next=first[y];first[y]=len;t[len].o=len-1;
 25 }
 26 
 27 int c[Maxn];
 28 
 29 int st,ed;
 30 
 31 queue<int > q;
 32 int dis[Maxn];
 33 bool bfs()
 34 {
 35     while(!q.empty()) q.pop();
 36     memset(dis,-1,sizeof(dis));
 37     q.push(st);dis[st]=0;
 38     while(!q.empty())
 39     {
 40         int x=q.front();
 41         for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 42         {
 43             int y=t[i].y;
 44             if(dis[y]==-1)
 45             {
 46                 dis[y]=dis[x]+1;
 47                 q.push(y);
 48             }
 49         }
 50         q.pop();
 51     }
 52     if(dis[ed]==-1) return 0;
 53     return 1;
 54 }
 55 
 56 int ffind(int x,int flow)
 57 {
 58     if(x==ed) return flow;
 59     int now=0;
 60     for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 61     {
 62         int y=t[i].y;
 63         if(dis[y]==dis[x]+1)
 64         {
 65             int a=ffind(y,mymin(flow-now,t[i].f));
 66             t[i].f-=a;
 67             t[t[i].o].f+=a;
 68             now+=a;
 69         }
 70         if(now==flow) break;
 71     }
 72     if(now==0) dis[x]=-1;
 73     return now;
 74 }
 75 
 76 int max_flow()
 77 {
 78     int ans=0;
 79     while(bfs())
 80     {
 81         ans+=ffind(st,INF);
 82     }
 83     return ans;
 84 }
 85 
 86 bool qq[Maxn];
 87 
 88 void dfs(int x)
 89 {
 90     qq[x]=1;
 91     for(int i=first[x];i;i=t[i].next) if(!qq[t[i].y]&&t[i].f>0)
 92     {
 93         dfs(t[i].y);
 94     }
 95 }
 96 
 97 int main()
 98 {
 99     int m,n,sum=0;
100     scanf("%d%d",&m,&n);
101     len=0;
102     memset(first,0,sizeof(first));
103     for(int i=1;i<=m;i++)
104     {
105         scanf("%d",&c[i]);
106         sum+=c[i];
107         while(1)
108         {
109             int x;
110             scanf("%d",&x);
111             if(x==-1) break;
112             ins(i,x+m,INF);
113         }
114     }
115     st=n+m+1;ed=st+1;
116     for(int i=1;i<=m;i++) ins(st,i,c[i]*10000+1);
117     for(int i=1;i<=n;i++)
118     {
119         int x;
120         scanf("%d",&x);
121         ins(i+m,ed,x*10000);
122     }
123     int x=max_flow();
124     memset(qq,0,sizeof(qq));
125     dfs(st);
126     /*for(int i=1;i<=len;i+=2) 
127     {
128         if(t[i].x==st&&t[i].f>0) qq[t[i].y]=1;
129         if(t[i].y==ed&&t[i].f==0)
130             qq[t[i].x]=1;
131     }*/
132     for(int i=1;i<=m;i++) if(qq[i]) printf("%d ",i);printf("\n");
133     for(int i=m+1;i<=m+n;i++) if(qq[i]) printf("%d ",i-m);printf("\n");
134     printf("%d\n",sum-x/10000);
135     return 0;
136 }
View Code

 

那啥*10000就是方大边权。。。ORZ。。。

 

 

2016-11-04 09:42:22

posted @ 2016-11-04 09:37  konjak魔芋  阅读(273)  评论(0编辑  收藏  举报