[网络流24题]太空飞行计划问题(最小割)

题意

给定n个实验,m个机器,选一个实验得到ai价值,选一个机器有bi代价,每一个实验必须要某些机器参与才能进行,问获得的最大价值

思路

对于每一个实验,分为两种选择:

  1. 选取这个实验,那么必须选取其对应的所有机器

  2. 不选这个实验,那么其对应的机器只受到其他实验选择的影响

也就是说在实验和机器中选择一部分“放弃”,使得总价值最大,考虑最小割

建两排点分别表示实验和机器,用权值为ai的边连接源点与实验,权值为bi的边连接机器与汇点,实验与其相关的机器连权值为INF的边,那么ans=sigma(ai)-最小割

通过这样建图就可以发现,由于中间连边为INF不可能被切掉,所以被切掉的边只能是实验或者它对应的所有机器

由于原题还需要输出方案,只需要输出最后一次bfs(即没有増广路)可以到达的实验以及其对应的机器即可

Code:

#include<bits/stdc++.h>
#define N 105
using namespace std;
const int INF = 2000000000;
int n,m,s=101,t=102,sum;
bool flag;
int dep[N];
struct Edge
{
	int next,to,flow;
}edge[10005];int head[N],cur[N],cnt=1;
void add_edge(int from,int to,int flow)
{
	edge[++cnt].next=head[from];
	edge[cnt].to=to;
	edge[cnt].flow=flow;
	head[from]=cnt;
}
void add(int from,int to,int flow)
{
	add_edge(from,to,flow);
	add_edge(to,from,0); 
}
int read()
{
    char ch=' ';int res=0;
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) res=res*10+ch-'0',ch=getchar();
    if(ch=='
') flag=1;
    return res;
}
bool bfs()
{
	queue<int> q;
	memset(dep,0,sizeof(dep));
	for(int i=1;i<=104;++i) cur[i]=head[i];
	q.push(s); dep[s]=1;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=head[u];i;i=edge[i].next)
		{
			int v=edge[i].to;
			if(edge[i].flow<=0||dep[v]) continue;
			dep[v]=dep[u]+1;
			q.push(v);
			if(v==t) return true;
		}
	}
	return false;
}
int dfs(int rt,int rest)
{
	if(rt==t) return rest;
	int used=0;
	for(int i=cur[rt];i;i=edge[i].next)
	{
		cur[rt]=i;
		int v=edge[i].to;
		if(dep[v]==dep[rt]+1&&edge[i].flow>0)
		{
			int k=dfs(v,min(edge[i].flow,rest-used));
			if(!k) dep[v]=0;
			edge[i].flow-=k;
			edge[i^1].flow+=k;
			used+=k;
		}
	}
	return used;
}
int dinic()
{
	int ret=0,flow=0;
	while(bfs()) while((flow=dfs(s,INF))) ret+=flow;
	return ret;
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;++i)
	{
		int earn=read();flag=0;
		sum+=earn;
		add(s,i,earn);
		while(!flag)
		{
			int ned=read();
			add(i,ned+50,INF);
		}
	}
	for(int i=1;i<=m;++i)
	{
		int cost=read();
		add(i+50,t,cost);
	}
	int maxx=dinic();
	for(int i=1;i<=50;++i) if(dep[i]) printf("%d ",i);
	printf("
");
	for(int i=1;i<=50;++i) if(dep[i+50]) printf("%d ",i);
	printf("
");
	printf("%d
",sum-maxx);
	return 0;
}
原文地址:https://www.cnblogs.com/Chtholly/p/11203688.html