【网络流24题】太空飞行计划
【问题描述】
W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={ I1, I2,…,In }。实验Ej 需要用到的仪器是I的子集Rj∈I。配置仪器Ik 的费用为ck 美元。实验Ej 的赞助商已同意为该实验结果支付pj 美元。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
【题解】
最大权闭合图,最大权值就是tot-最小割,跑一遍dinic就行了。
至于输出方案,用贪心的思路,level不为0的点就是了。
吐槽:这题的输入非常奇葩,用一下代码,可能运行不了,但在cojs上能过,如果要在本地运行,请使用被注释掉的部分。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<ctime> #include<algorithm> using namespace std; #define MAXN 250*2 #define INF 1000000000 struct node{int y,next,v,rel;}e[MAXN]; int n,m,S,T,len,sum,ans,Link[MAXN],level[MAXN],q[MAXN]; inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } void insert(int x,int y,int v) { e[++len].next=Link[x];Link[x]=len;e[len].y=y;e[len].v=v;e[len].rel=len+1; e[++len].next=Link[y];Link[y]=len;e[len].y=x;e[len].v=0;e[len].rel=len-1; } bool bfs() { memset(level,-1,sizeof(level)); level[S]=0; q[1]=S; int head=0,tail=1; while(++head<=tail) { for(int i=Link[q[head]];i;i=e[i].next) if(level[e[i].y]<0&&e[i].v) { q[++tail]=e[i].y; level[q[tail]]=level[q[head]]+1; } } return level[T]>=0; } int dinic(int x,int flow) { if(x==T) return flow; int d=0,maxflow=0; for(int i=Link[x];i&&maxflow<flow;i=e[i].next) if(e[i].v&&level[e[i].y]==level[x]+1) if(d=dinic(e[i].y,min(e[i].v,flow-maxflow))) { maxflow+=d; e[i].v-=d; e[e[i].rel].v+=d; } if(!maxflow) level[x]=-1; return maxflow; } void solve() { int d=0; while(bfs()) while(d=dinic(S,INF)) ans+=d; } int main() { freopen("shuttle.in","r",stdin); freopen("shuttle.out","w",stdout); n=read(); m=read(); S=0; T=n+m+1; for(int i=1;i<=n;i++) { int v; scanf("%d",&v); sum+=v; insert(S,i,v); //char ch=getchar(); //while(ch!=10) {int x; scanf("%d",&x); insert(i,x+n,INF); ch=getchar();} int x,y; while(scanf("%d%c",&x,&y)) { insert(i,x+n,INF); if(y=='\r') break; } } for(int i=1;i<=m;i++) { int v=read(); insert(i+n,T,v); } solve(); for(int i=1;i<=n;i++) if(level[i]!=-1) printf("%d ",i); printf("\n"); for(int i=1;i<=m;i++) if(level[i+n]!=-1) printf("%d ",i); printf("\n"); printf("%d\n",sum-ans); return 0; }