题目描述
W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,…In}。实验Ej需要用到的仪器是I的子集RjÍI。配置仪器Ik的费用为ck美元。实验Ej的赞助商已同意为该实验结果支付pj美元。W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。
对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
分析
建图
1 :构造一个图 N ,顶点有 Ii(1<=i<=n) , Ej(1<=j<=m) 以及一个源 S 和汇 T
2 :从源点出发,向每个实验 Ei 引出一条容量为 Pi 的有向边
3 :从每个仪器 Ij 出发,向汇点引出一条容量为 Ck 的有向边
4 :每个实验分别向所需的仪器引出一条容量为 +∞ 的有向边
统计出所有实验的收入只和Total,求网络最大流Maxflow,最大收益就是Total-Maxflow。对应的解就是最小割划分出的S集合中的点,也就是最后能从S访问到的顶点的集合。
坑爹的c++的行输入
code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
struct arr{
int x,y,w;
int op;
int next;
}edge[1000000];
int ls[4000];
int v[4000];
int w[4000];
int f[4000];
int queue[5000];
int dis[4000];
int s,t;
int n,m,nn;
int min1;
int ans;
void er(int ww)
{
w[nn]=ww;
}
void add(int x,int y,int w)
{
nn++;
edge[nn].x=x;
edge[nn].y=y;
edge[nn].w=w;
edge[nn].op=nn+1;
edge[nn].next=ls[x];
ls[x]=nn;
v[x]=nn;
er(w);
nn++;
edge[nn].x=y;
edge[nn].y=x;
edge[nn].w=w;
edge[nn].op=nn-1;
edge[nn].next=ls[y];
ls[y]=nn;
v[y]=nn;
er(0);
}
bool bfs()
{
memset(dis,-1,sizeof(dis));
memset(queue,0,sizeof(queue));
int head,tail;
head=0; tail=1;
queue[head]=0;
dis[0]=0;
do
{
head++;
int i=ls[queue[head]];
while (i!=0)
{
if ((w[i]>0)&&(dis[edge[i].y]==-1))
{
dis[edge[i].y]=dis[edge[i].x]+1;
tail++;
queue[tail]=edge[i].y;
if (edge[i].y==t) return true;
}
i=edge[i].next;
}
}while (head<tail);
return false;
}
bool find(int x,int num)
{
if (x!=s) min1=min(min1,w[num]);
if (x==t) return true;
for (int i=v[x];i!=0;i=edge[i].next)
{
int x=edge[i].x;
int y=edge[i].y;
if ((dis[x]+1==dis[y])&&(w[i]!=0)&&(find(y,i)))
{
f[x]=y;
w[i]-=min1;
w[edge[i].op]+=min1;
return true;
}
}
return false;
}
int dinic(int xx)
{
ans=xx;
while (bfs())
{
min1=2000000000;
find(s,0);
ans=ans-min1;
}
bfs();
for (int i=1;i<=n;i++)
if (dis[i]!=-1) printf("%d ",i);
printf("\n");
for (int i=n+1;i<=n+m;i++)
if (dis[i]!=-1) printf("%d ",i-n);
printf("\n");
printf("%d",ans);
}
int main()
{
int ans=0;
scanf("%d%d",&n,&m);
int x,y;
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
add(0,i,x);
ans=ans+x;
char ch=getchar();
while((ch=getchar())!='\n')
{
int x=0;
x=ch-'0';
while((ch=getchar())&&ch>='0'&&ch<='9')
x=x*10+ch-'0';
add(i,x+n,20000000);
if(ch=='\n')break;
}
}
s=0;
t=n+m+1;
for (int i=n+1;i<=n+m;i++)
{
int x;
scanf("%d",&x);
add(i,t,x);
}
dinic(ans);
return 0;
}