Sample Input
1 1 2
C1 D1
D1 C1
1 2 4
C1 D1
C1 D1
C1 D2
D2 C1
Sample Output
1
3
题意: 有n只毛,m只狗,p个孩子,每个孩子有喜欢的也有喜欢的动物,喜欢猫就不喜欢狗,反之亦然;
把孩子喜欢的留着,不喜欢的搬走,则孩子会高兴;问怎样搬动物,最大能让多少孩子高兴;
输入,第一个为喜欢,第二个为不喜欢;
思路: 把孩子看成一个点,a喜欢的b不喜欢,则ab矛盾,连一条边;则得到一个图;我们的目标是在这个图中找到
一个最大点独立集,即这个集合中的孩子任意两个都不矛盾,也就是可以同时高兴;
就简化为,建图, 最大点独立集 = 顶点数 - 匹配数 ; 求二分匹配 !!
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=2000 ;
int match[N];
bool vist[N];
char yes[N][5],no[N][5];
vector<int>E[N];
int dfs(int u)
{
for(int i = 0 ; i < E[u].size() ; i++)
{
int v=E[u][i];
if(!vist[v])
{
vist[v]=true;
if(match[v]==-1 || dfs(match[v]))
{
match[v]=u;
return 1 ;
}
}
}
return 0;
}
int main()
{
int n,m,p;
while(~scanf("%d%d%d",&n,&m,&p))
{
for(int i=0;i<N;i++)
E[i].clear();
for(int i = 0 ; i < p ; i++)
scanf("%s%s",yes[i],no[i]); //喜欢的,不喜欢的
for(int i = 0 ; i < p ; i++)
for(int j = i+1 ; j < p ; j++)
if(strcmp(yes[i],no[j])==0 || strcmp(yes[j],no[i])==0)
{ //矛盾的孩子建边
E[i].push_back(j);
E[j].push_back(i);
}
int ans = 0 ;
memset(match,-1,sizeof(match));
for(int i = 0 ; i < p ; i++)
{
memset(vist,false,sizeof(vist));
ans += dfs(i) ; //求匹配
}
//printf("%d**",ans);
printf("%d\n",p-ans/2); //因为建的是双向边(相当于拆点),所以匹配数除以2
}
return 0;
}
1 1 2
C1 D1
D1 C1
1 2 4
C1 D1
C1 D1
C1 D2
D2 C1
Sample Output
1
3
题意: 有n只毛,m只狗,p个孩子,每个孩子有喜欢的也有喜欢的动物,喜欢猫就不喜欢狗,反之亦然;
把孩子喜欢的留着,不喜欢的搬走,则孩子会高兴;问怎样搬动物,最大能让多少孩子高兴;
输入,第一个为喜欢,第二个为不喜欢;
思路: 把孩子看成一个点,a喜欢的b不喜欢,则ab矛盾,连一条边;则得到一个图;我们的目标是在这个图中找到
一个最大点独立集,即这个集合中的孩子任意两个都不矛盾,也就是可以同时高兴;
就简化为,建图, 最大点独立集 = 顶点数 - 匹配数 ; 求二分匹配 !!
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=2000 ;
int match[N];
bool vist[N];
char yes[N][5],no[N][5];
vector<int>E[N];
int dfs(int u)
{
for(int i = 0 ; i < E[u].size() ; i++)
{
int v=E[u][i];
if(!vist[v])
{
vist[v]=true;
if(match[v]==-1 || dfs(match[v]))
{
match[v]=u;
return 1 ;
}
}
}
return 0;
}
int main()
{
int n,m,p;
while(~scanf("%d%d%d",&n,&m,&p))
{
for(int i=0;i<N;i++)
E[i].clear();
for(int i = 0 ; i < p ; i++)
scanf("%s%s",yes[i],no[i]); //喜欢的,不喜欢的
for(int i = 0 ; i < p ; i++)
for(int j = i+1 ; j < p ; j++)
if(strcmp(yes[i],no[j])==0 || strcmp(yes[j],no[i])==0)
{ //矛盾的孩子建边
E[i].push_back(j);
E[j].push_back(i);
}
int ans = 0 ;
memset(match,-1,sizeof(match));
for(int i = 0 ; i < p ; i++)
{
memset(vist,false,sizeof(vist));
ans += dfs(i) ; //求匹配
}
//printf("%d**",ans);
printf("%d\n",p-ans/2); //因为建的是双向边(相当于拆点),所以匹配数除以2
}
return 0;
}