2018青岛站:Magic potion(最大流)

其实很明显是最大流的模板题了

但是傻币的我居然一开始没想到

后来一直尝试用费用流甚至上下界网络流来解决…

因为每个英雄可以免费杀死一个怪物

1 所以源点理应向英雄连一条流量1的边

使 k , 使 但是还可以使用k次药水啊,要命的是你必须把使用药水的流量和免费的流量分开来

. . . 其实也很简单...

, k 使 另设置一个限制源点,源点向限制源点连流量k的边代表使用魔法

1 使 限制源点向每个英雄连流量1的边表示给某个英雄使用魔法

啥问题也没了…

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e6+10;
const int inf=1e9;
int n,m,s,t,S,dis[maxn],k;
struct edge{
	int to,nxt,flow;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int flow){
	d[++cnt]=(edge){v,head[u],flow},head[u]=cnt;
	d[++cnt]=(edge){u,head[v],0},head[v]=cnt;
}
bool bfs()
{
	for(int i=0;i<=t;i++)	dis[i]=0;
	dis[s]=1;
	queue<int>q; q.push( s );
	while( !q.empty() )
	{
		int u=q.front(); q.pop();
		for(int i=head[u];i;i=d[i].nxt )
		{
			int v=d[i].to;
			if( d[i].flow&&dis[v]==0 )
			{
				dis[v]=dis[u]+1;
				if( v==t )	return true;
				q.push( v );
			}
		}
	}
	return false;
}
int dinic(int u,int flow)
{
	if( u==t )	return flow;
	int res=flow;
	for(int i=head[u];i&&res;i=d[i].nxt )
	{
		int v=d[i].to;
		if( dis[v]==dis[u]+1&&d[i].flow)
		{
			int temp=dinic(v,min(res,d[i].flow) );
			if( temp==0 )	dis[v]=0;
			res-=temp;
			d[i].flow-=temp;
			d[i^1].flow+=temp;
		}
	}
	return flow-res;
}
int main()
{
	cin >> n >> m >> k;
	s=0,S=n+m+1,t=S+1;
	add(s,S,k);
	for(int i=1;i<=n;i++)
	{
		add(s,i,1);
		add(S,i,1);
		int x; cin >> x;
		while( x-- )
		{
			int l; cin >> l;
			add(i,l+n,1);
		} 
	}
	for(int i=1;i<=m;i++)	add(i+n,t,1);
	int ans=0;
	while( bfs() )	ans+=dinic(s,inf);
	cout << ans;
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/108351204