1. 程式人生 > >[網路流24題-11]太空飛行問題

[網路流24題-11]太空飛行問題

太空飛行計劃問題

貌似叫最大權閉合子圖?(反正這些高階大氣上檔次的名詞我都不知道

建模比較有趣

先想最大流 大概是源連實驗 實驗連儀器 儀器連匯 然後發現無論怎麼分配都做不到捆綁並只計算一次費用 棄療

最小費用最大流 怎麼建都是所有點都選才是最大流 更不靠譜 棄療

最小割(不要問我為什麼沒想上下界 因為我還沒學會

我們發現按照上述最大流的建圖方法 然後實驗和儀器之間流量為inf 這樣的話就可以保證一個實驗和他需要的儀器捆綁

實驗和源點之間是貢獻 儀器和匯點之間是費用 這樣的話就構成了這個模型

貢獻可以這麼考慮 本來我們選擇的是所有的總貢獻 所以割掉一條邊其實是減去了貢獻 費用更好理解了 割掉了就是花掉了嘛

所以我們根據最大流=最小割跑一遍最大流

然後看跟源點相連的實驗和儀器就是要選的 所以這個問題就解決啦

這個題讀入真的毒瘤(大霧)

附程式碼。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#define inf 20021225
#define ll long long
using namespace std;
queue<int> 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<int> 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;
}