题意:有n个英雄,m个怪物,k瓶药水,每个英雄只能选择杀死自己能杀的怪物集合里的怪物,一个英雄能杀死一个怪物,但是如果一个英雄喝了一瓶药水之后,他能多杀一个怪物,一个英雄最多喝一瓶药水。问你这n个英雄最多能杀死多少只怪物。
思路:二分图的经典题,可以利用匈牙利算法解决。因为题目多了可以使用药水的条件,因此我们可以使用两次匈牙利算法来解决这道题,第一次匈牙利算法可以找出每个英雄在不使用药水的情况下最多杀死多少怪物(sum1),第二次匈牙利算法假设每个英雄都有使用一次药水的机会,看看他们又能杀死多少只怪物(sum2)。将sum2与k作比较,如果sum2>=k,那么ans=k+sum1,如果sum2<k,那么ans=sum2+sum1.
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=5100;
int h[maxn],e[maxn],ne[maxn],idx;
bool st[maxn];
int match[maxn];
void init()
{
memset(h,-1,sizeof h);
idx=0;
}
void add_to_head(int a,int b)
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx;
idx++;
}
bool find(int x)
{
for(int i=h[x];i!=-1;i=ne[i])
{
int j=e[i];
if(!st[j])
{
st[j]=true;
if(match[j]==0||find(match[j]))
{
match[j]=x;
return true;
}
}
}
return false;
}
int main()
{
init();
int n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
{
int nn,x;
scanf("%d",&nn);
while(nn--)
{
scanf("%d",&x);
add_to_head(i,x);
}
}
int sum1=0,sum2=0;
for(int i=1;i<=n;i++)
{
memset(st,0,sizeof st);
if(find(i)) sum1++;
}
for(int i=1;i<=n;i++)
{
memset(st,0,sizeof st);
if(find(i)) sum2++;
}
if(sum2>=k) cout<<k+sum1;
else cout<<sum1+sum2;
return 0;
}
第三个数据点一直runtime error,检查不出来错误,后来发现是数组开小了,以为开到510就够了,没有认真分析题目。用邻接表来写匈牙利的时候,h[N]数组中的N表示点的个数,e[M],ne[M]表示边的个数,这个题目中其实只给了点的个数,边的个数是n*m,至少要2500个的。