[网络流24题-11]太空飞行问题

太空飞行计划问题

貌似叫最大权闭合子图?(反正这些高端大气上档次的名词我都不知道

建模比较有趣

先想最大流 大概是源连实验 实验连仪器 仪器连汇 然后发现无论怎么分配都做不到捆绑并只计算一次费用 弃疗

最小费用最大流 怎么建都是所有点都选才是最大流 更不靠谱 弃疗

最小割(不要问我为什么没想上下界 因为我还没学会

我们发现按照上述最大流的建图方法 然后实验和仪器之间流量为inf 这样的话就可以保证一个实验和他需要的仪器捆绑

实验和源点之间是贡献 仪器和汇点之间是费用 这样的话就构成了这个模型

贡献可以这么考虑 本来我们选择的是所有的总贡献 所以割掉一条边其实是减去了贡献 费用更好理解了 割掉了就是花掉了嘛

所以我们根据最大流=最小割跑一遍最大流

然后看跟源点相连的实验和仪器就是要选的 所以这个问题就解决啦

这个题读入真的毒瘤(大雾)

附代码。

#include
#include
#include
#include
#include
#include
#include
#define inf 20021225
#define ll long long
using namespace std;
queue que;
int dis[110],cnt=1,in[110],s,t;
struct edge{int to,lt,f;}e[60000];
void add(int x,int y,int f)
{
	e[++cnt].to=y;e[cnt].lt=in[x];e[cnt].f=f;in[x]=cnt;
	e[++cnt].to=x;e[cnt].lt=in[y];e[cnt].f=0;in[y]=cnt;
}
bool bfs(int f)
{
	while(!que.empty())	que.pop();
	memset(dis,0,sizeof(dis));
	que.push(s);dis[s]=1;
	while(!que.empty())
	{
		int x=que.front();que.pop();//printf("%d",x);
		for(int i=in[x];i;i=e[i].lt)
		{
			int y=e[i].to;
			//printf("%d %d\n",y,e[i].f);
			if(!dis[y]&&e[i].f)
			{
				dis[y]=dis[x]+1;//printf("%d\n",y);
				if(y==t&&f)	return 1;
				que.push(y);
			}
		}
	}
	return 0;
}
int dfs(int x,int flow)
{
	if(x==t||!flow)	return flow;
	int cur=flow;
	for(int i=in[x];i;i=e[i].lt)
	{
		int y=e[i].to;
		if(dis[y]==dis[x]+1&&e[i].f)
		{
			int tmp=dfs(y,min(cur,e[i].f));
			e[i].f-=tmp;e[i^1].f+=tmp;cur-=tmp;
			if(!cur)	return flow;	
		}
	}
	dis[x]=-1;
	return flow-cur;
}
bool vis[110];
int dinic()
{
	int ans=0;
	while(bfs(1))	ans+=dfs(s,inf);
	bfs(0);return ans;
}
char tools[10000];
int c[110],ee[110];
vector v[110];
int main()
{
	int n,m,i,tot=0;
	scanf("%d%d",&m,&n);
	s=m+n+1;t=s+1;
	for(i=1;i<=m;i++)
	{
		scanf("%d",&c[i]);
		add(s,i,c[i]);
		memset(tools,0,sizeof tools);
		cin.getline(tools,10000);
		int ulen=0,tool;
		while (sscanf(tools+ulen,"%d",&tool)==1)
		{
			add(i,tool+m,inf);v[i].push_back(tool);
			//printf("%d\n",tool);
		    if (tool==0) 
		        ulen++;
		    else {
		        while (tool) {
		            tool/=10;
		            ulen++;
		        }
		    }
		    ulen++;
		}
	}
	for(i=1;i<=n;i++)	scanf("%d",&ee[i]),add(i+m,t,ee[i]);
	dinic();
	for(i=1;i<=m;i++)
		if(dis[i])
			printf("%d ",i),tot+=c[i];
	printf("\n");
	for(i=1;i<=n;i++)
		if(dis[i+m])	printf("%d ",i),tot-=ee[i];
	printf("\n%d\n",tot);
	return 0;
}

 

你可能感兴趣的:(题解,网络流,————图论————)