(最大流,二分圖的多重匹配) Magic Potion

myq0201發表於2020-10-24

在這裡插入圖片描述
題意:n個人,m個怪物,k瓶藥水,每個人可以打死對應的集合裡面的一個怪物,一碰藥水可以讓一個人多打死一個怪物,每個人最多隻能用一瓶藥水,問最多能打死多少個怪物
思路:想到了匹配,然後用最大流做,一開始想的建圖是從超級原點連一條容量是n+k的邊到虛擬節點,然後虛擬節點與所有勇士連一條容量是2的邊,然後勇士與對應的怪物連1的邊,怪物與匯點連1的邊跑最大流,然後wa了,錯誤在於我們這樣做預設勇士可以用藥了,然後k等於0的時候,答案就不對了,所以正解是超級源點和所有勇士連1的邊,藥水節點與勇士連1的邊,超級源點與藥水連k的邊,勇士和對應怪物連1的邊,怪物與匯點連1的邊,跑最大流
ac程式碼:

#include<iostream>
#include<cstring>
using namespace std;
const int N=10000,M=60010;
int h[N],ne[M],e[M],idx,f[M];
void add(int a,int b,int c)
{
	e[idx]=b,ne[idx]=h[a],f[idx]=c,h[a]=idx++;
	e[idx]=a,ne[idx]=h[b],f[idx]=0,h[b]=idx++;
}
const int INF=1e8;
int S0,S,T,n,m,k;
int d[N];
int cur[N];
int q[N];
int bfs()
{
	int hh=0,tt=0;
	memset(d,-1,sizeof d);
	//cout<<S<<endl;
	d[S]=0;
	cur[S]=h[S];
	q[0]=S;
	while(hh<=tt)
	{
		int t=q[hh++];
		for(int i=h[t];~i;i=ne[i])
		{
			int j=e[i];
			if(f[i]&&d[j]==-1)
			{
				d[j]=d[t]+1;
				cur[j]=h[j];
				if(j==T)	return true;
				q[++tt]=j;
			}
		}
	}
	return false;
}	
int dfs(int u,int limit)
{
	//cout<<u<<endl;
	if(u==T)
		return limit;
	int flow=0;
	for(int i=cur[u];~i&&flow<limit;i=ne[i])
	{
		int j=e[i];
		cur[u]=i;
		if(d[j]==d[u]+1 && f[i])
		{
			int t=dfs(j,min(f[i],limit-flow));
			if(!t)
			d[j]=-1;
			f[i]-=t;
			flow+=t;
			f[i^1]+=t;
		}
	}
	return flow;
}
int dinic()
{
	int res=0,flow;
	while(bfs())
	while(flow=dfs(S,INF))
	res+=flow;
	return res;
}
int main()
{
	cin >> n >> m >> k;
	//cout<<n<<' '<<m<<' '<<k<<endl;
	memset(h,-1,sizeof h);
	for(int i=1;i<=n;i++)
	{
		int t;
		cin>>t;
		while(t--)
		{
			int x;
			cin>>x;
			add(i,n+x,1);
		}
	}
	for(int i=1;i<=n;i++)
		add(n+m+1,i,1),add(0,i,1);
	for(int i=n+1;i<=n+m;i++)
		add(i,n+m+2,1);
		add(0,n+m+1,k);
		S=0;
		T=n+m+2;
		cout<<dinic()<<endl;
}

相關文章