思路
首先考虑二分图,将 n n n 个英雄和 m m m 个怪物看作是两个集合中的结点,英雄打怪兽的关系看作是边。那么求最大匹配就行了。
考虑到一个英雄最多还能吃一瓶药,所以,将 n n n 个英雄结点,拆为 2 n 2n 2n 个英雄结点。前 n n n 个结点代表吃药前的英雄,后 n n n 个结点代表对应的吃药后的英雄。显然,一个英雄,吃药后的边与吃药前的边连接的怪兽相同。(暂时考虑有无数瓶药)
先求 n n n 个英雄没吃药前的最大匹配 a n s 1 ans1 ans1,再求 n n n 个吃药后的英雄的最大匹配 a n s 2 ans2 ans2。那么, a n s 1 + a n s 2 ans1+ans2 ans1+ans2 就代表着,当有无数瓶药,每个英雄最多吃一瓶药时,能消灭的怪兽的最大数量。
当有 k k k 瓶药时,那么答案就为 a n s 1 + m i n ( k , a n s 2 ) ans1+min(k,ans2) ans1+min(k,ans2)。
#include<bits/stdc++.h>
#define H(x) (x+500)
using namespace std;
const int N=1510,M=2.3e6;
int head[N],ver[M],Next[M],tot;
int n,m,k,t,vis[N],match[N],ans1,ans2;
void add(int u,int v){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
}
bool dfs(int x){
for(int i=head[x],y;i;i=Next[i]){
if(!vis[y=ver[i]]){
vis[y]=1;
if(!match[y]||dfs(match[y])){
match[y]=x; return true;
}
}
}
return false;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
int k; cin>>k;
for(int j=1;j<=k;j++){
cin>>t;
add(H(i),t),add(t,H(i));
add(H(i+n),t),add(t,H(i+n));
}
}
for(int i=1;i<=(n<<1);i++){
memset(vis,0,sizeof(vis));
if(dfs(H(i))) ans1+=(i<=n),ans2+=(i>n);
}
cout<<ans1+min(ans2,k)<<"\n";
}