題目大意
有n個人,有c只貓與d只狗,每個人要麼喜歡一隻狗且討厭一隻貓,要麼喜歡一隻貓且討厭一隻狗,所以每個人都希望自己喜歡的被留下,自己討厭的被帶走,這樣這個人就會滿足,現在你需要找到一個貓狗集合方案,使得滿足的人儘量多,求最多的滿足人數。
思路
圖很大,且樣例很多,不能暴力建圖(就是每個人除了對自己討厭的東西之外都建邊),所以需要思維優化。可以這樣考慮,如果一個人喜歡的貓或狗是另一個人所討厭的,那麼這兩個人肯定不會同時滿足,用二分圖的思想就是一條邊不能同時選擇兩個端點。這樣,我們n^2暴力建二分圖,如果兩個人有衝突,在二分圖中建立邊i->j,這樣求出來就是二分圖最小覆蓋,他的反面就是我們要求的最大獨立集,也就是ans=n-最大匹配。
#include <bits/stdc++.h>
using namespace std;
const int maxn=500+10;
vector<int>G[maxn*2];
pair<string,string>P[maxn];
void init(int c,int d,int n){
for(int i=0;i<=n;i++)
{
G[i].clear();
P[i].first=P[i].second="";
}
}
void Build(int n){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)continue;
if(P[i].first==P[j].second||P[i].second==P[j].first){
G[i].push_back(j);
}
}
}
}
int vis[maxn];
int link[maxn];
bool Find(int x)
{
for(int i=0;i<G[x].size();i++)
{
int v=G[x][i];
if(!vis[v])
{
vis[v]=true;
if(link[v]==-1||Find(link[v]))
{
link[v]=x;
return true;
}
}
}
return false;
}
int Hungery(int n)
{
int ans=0;
for(int i=1;i<=n;i++)
{
memset(vis,false,sizeof(vis));
if(Find(i))
ans++;
}
return ans;
}
signed main(){
int T;
scanf("%d",&T);
while(T--){
int c,d,v;
scanf("%d%d%d",&c,&d,&v);
init(c,d,v);
for(int i=1;i<=v;i++){
string s1,s2;
cin>>s1>>s2;
P[i]=make_pair(s1,s2);
}
Build(v);
memset(link,-1,sizeof(link));
int ans=Hungery(v);//最大匹配數
printf("%d\n",v-ans/2);
}
return 0;
}