P2762 太空飞行计划问题

(color{#0066ff}{题目描述})

W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,…In}。实验Ej需要用到的仪器是I的子集RjÍI。配置仪器Ik的费用为ck美元。实验Ej的赞助商已同意为该实验结果支付pj美元。W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。

对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。

(color{#0066ff}{输入格式})

第1行有2 个正整数m和n。m是实验数,n是仪器数。接下来的m 行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。最后一行的n个数是配置每个仪器的费用。

(color{#0066ff}{输出格式})

第1 行是实验编号;第2行是仪器编号;最后一行是净收益。

(color{#0066ff}{输入样例})

2 3
10 1 2
25 2 3
5 6 7

(color{#0066ff}{输出样例})

1 2
1 2 3
17

(color{#0066ff}{数据范围与提示})

有spj

(n,m leq 50)

(color{#0066ff}{题解})

利润=总收入-总花费

我们让S与每个实验连容量为实验价值的边

每个实验向相应仪器连inf的边

每个仪器向T连容量为工具费用的边

这样跑出的最小割保证了实验与仪器的选与不选

我们统计所有实验的收入

最小割中,我们把不选的实验的收入也看做花费

可以理解为,如果某个实验的收益为负数,但是它用到的仪器能为别的实验所用,那么就相当与你花了这个实验的赞助商给你的钱为别的实验买仪器

具象化在图上,就是那个仪器给这个实验一个流,把这个实验流出去的抵消掉了

如果是怎么买仪器都不划算的实验,这样的实验有一个特点,因为它不能供给仪器的需求,所以它到S的残量一定是0

因为它所需仪器的费用比自己的收益还大,那么经过网络流,它一定全流过去了

而那些划算的实验,会流不满(因为没收益)

所以我们找到满的,就是不要的

直接找dep不为0的就行了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<cmath>
#define _ 0
#define LL long long
inline LL in()
{
	LL x=0,f=1; char ch;
	while(!isdigit(ch=getchar()))(ch=='-')&&(f=-f);
	while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
	return x*f;
}
int n,m;
struct node 	
{
	int to,dis,nxt;
	node(int to=0,int dis=0,int nxt=0):to(to),dis(dis),nxt(nxt){}
}e[105050];
int cnt=1,s,t;
int head[1050],cur[1050],dep[1050];
bool vis[1050];
std::queue<int> q;
std::string fuck;
int ans;
const int inf=0x7fffffff;
inline void add(int from,int to,int dis)
{
	e[++cnt]=node(to,dis,head[from]);
	head[from]=cnt;
}
inline bool bfs()
{
	for(int i=s;i<=t;i++) dep[i]=0,cur[i]=head[i];
	q.push(s);
	dep[s]=1;
	while(!q.empty())
	{
		int tp=q.front(); q.pop();
		for(int i=head[tp];i;i=e[i].nxt)
		{
			int go=e[i].to;
			if(!dep[go]&&e[i].dis>0)
			{
				dep[go]=dep[tp]+1;
				q.push(go);
			}
		}
	}
	return dep[t];
}
inline int dfs(int x,int change)
{
	if(x==t||!change) return change;
	int flow=0,ls;
	for(int i=cur[x];i;i=e[i].nxt)
	{
		int go=e[i].to;
		cur[x]=i;
		if(dep[go]==dep[x]+1&&(ls=dfs(go,std::min(change,e[i].dis))))
		{
			change-=ls;
			flow+=ls;
			e[i].dis-=ls;
			e[i^1].dis+=ls;
			if(!change) break;
		}
	}
	return flow;
}
inline void dinic()
{
	int flow=0;
	while(bfs()) flow+=dfs(s,inf);
	for(int i=1;i<=m;i++) if(dep[i]) printf("%d ",i);
	putchar('
');
	for(int i=m+1;i<=m+n;i++) if(dep[i]) printf("%d ",i-m);
	printf("
%d",ans-flow);
}
int main()
{
	m=in(),n=in();
	s=0,t=n+m+1;
	int sb;
	for(int i=1;i<=m;i++)
	{
		add(s,i,sb=in()),add(i,s,0);
		ans+=sb;
		std::getline(std::cin,fuck);
		int x=0,o=0;
		while(o<(int)fuck.length())
		{
			x=0;
			while(!isdigit(fuck[o])&&o<(int)fuck.length()) o++;
			while(isdigit(fuck[o])) x=x*10+(fuck[o]^48),o++;
			if(x) add(i,m+x,inf),add(m+x,i,0);
			else break;
		}
	}
	for(int i=m+1;i<=m+n;i++) add(i,t,in()),add(t,i,0);
	dinic();
	return 0;
}
原文地址:https://www.cnblogs.com/olinr/p/10103460.html