2.太空飞行计划问题
题目描述 Description
W教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={
E1
,
E2
,…,
Em
},和进行这些实验需要使用的全部仪器的集合I={
I1
,
I2
,…
In
}。实验
Ej
需要用到的仪器是I的子集
Rj
⊆I。配置仪器
Ik
的费用为
ck
美元。实验
Ej
的赞助商已同意为该实验结果支付
pj
美元。W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额
输入描述 Input Description
第1行有2个正整数m和n。m是实验数,n是仪器数。接下来的m 行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。最后一行的n个数是配置每个仪器的费用。
输出描述 Output Description
将最佳实验方案输出,第1行是实验编号;第2行是仪器编号;最后一行是净收益
样例输入 Sample Input
2 3
10 1 2
25 2 3
5 6 7
样例输出 Sample Output
1 2
1 2 3
17
分析: 选和不选问题,转化为最小割模型,对于每个实验来说(不考虑其他实验),若是总的收益比总费用要大,那么就选择这个实验,否则不选,而这个题目只是将其整体化了而已
建图: S向每一个实验建一条容量为实验收益的边,实验向相关器材建一条容量为INF的边,器材向T建一条容量为花费的边
答案就是总收益减去最大流,S与实验相连的边若为满流则为选择该实验
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 2100000000
struct node {
int to;
int next;
int flow;
}e[10000];
int head[200];
int cur[200];
int n,m,s,t,tot=1;
int num[200];
int us[200];
int d[200];
int f[200];
char ch;
queue <int> q;
int read() {
int ans=0,flag=1;
ch=getchar();
while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') ans=ans*10+ch-'0',ch=getchar();
return ans*flag;
}
void addedge(int u,int v,int w) {
e[++tot].to=v;
e[tot].flow=w;
e[tot].next=head[u];
head[u]=tot;
e[++tot].to=u;
e[tot].flow=0;
e[tot].next=head[v];
head[v]=tot;
return ;
}
int dfs(int now,int flow) {
if(now==t)
return flow;
int use=0;
for(int i=cur[now];i;i=e[i].next) {
cur[now]=i;
if(d[e[i].to]+1==d[now] && e[i].flow>0) {
int temp=dfs(e[i].to,min(e[i].flow,flow-use));
use+=temp;
e[i].flow-=temp;
e[i^1].flow+=temp;
if(flow==use)
return use;
}
}
cur[now]=head[now];
if(!(--f[d[now]]))
d[s]=n+m+2;
++f[++d[now]];
return use;
}
int main() {
int ans=0;
n=read(),m=read();
s=0;t=n+m+1;
for(int i=1;i<=n;i++) {
int w=read(),to;
ans+=w;
addedge(0,i,w);
while(ch!='\n' && ch!='\r') {
to=read();
addedge(i,to+n,INF);
num[i]++;
}
}
for(int i=n+1;i<=n+m;i++) {
int w=read();
addedge(i,t,w);
}
f[0]=n+m+2;
while(d[s]<n+m+2)
ans-=dfs(s,1<<30);
q.push(0);
while(!q.empty()) {
int now=q.front();
q.pop();
for(int i=head[now];i;i=e[i].next) {
if(e[i].flow==0) continue;
if(!us[e[i].to]) {
q.push(e[i].to);
us[e[i].to]=true;
}
}
}
for(int i=1;i<=n;i++) {
if(us[i])
printf("%d ",i);
}
printf("\n");
for(int i=n+1;i<=n+m;i++) {
if(us[i])
printf("%d ",i-n);
}
printf("\n");
printf("%d",ans);
return 0;
}