题目大意:Frank是一个思想有些保守的老师。有一次,他需要带一些学生出去旅游,但又怕其中有一些学生在旅途中萌生爱意。为了降低这种事情发生的概率,他决定确保带出去的任意两个学生至少要满足下面4条中的一条:
1)身高相差大于40厘米。
2)性别相同。
3)最喜欢的音乐属于不同的类型。
4)最喜欢的体育比赛相同。
你的任务是帮助Frank挑选尽量多的学生,使得任意两个学生至少满足上述条件中的一条。
PS:简单来说就是有N个人,已知身高、性别、音乐、运动。要求选出尽可能多的人,使这些人两两之间至少满足四个条件之一。
思路:第一次做二分图匹配,也是看了题解才知道的这个板子,但本题不是单纯的用二分图匹配,这也就导致一开始只按照二分图匹配的应用思路来看并不符合本题的思路。本题要求的是两两互相不能组合的最大独立集体(最大独立集: 顶点集V中取 K个顶点,其两两间无连接),有公式知:(|最大独立集| = |V|-|最大匹配数|)。所以在用二分图匹配求出最大匹配数后,还要运用公式求出最大独立集,最大独立集才是本题所求。
AC代码:
#include <iostream>
#include <cstdio>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
using namespace std;
int v[501];
int line[501];
int n;
typedef struct pp
{
public:
int h;
char s;
string m;
string sp;
};
pp p[501];
bool panduan(pp a,pp b)
{
if(fabs(a.h-b.h)>40||a.m!=b.m||a.s==b.s||a.sp==b.sp)
return false;
return true;
}
bool judge(int x)
{
for(int i=0;i<n;i++)
{
if(!v[i]&&i!=x)
{
if(panduan(p[i],p[x]))
{
v[i]=1;
if(line[i]==0||judge(line[i]))
{
line[i]=x;
//line[x]=i;
return 1;
}
}
}
}
return 0;
}
int main()
{
int t,m;
scanf("%d",&t);
while(t--)
{
memset(line,0,sizeof(line));
int ans=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
cin>>p[i].h;
cin>>p[i].s;
cin>>p[i].m;
cin>>p[i].sp;
}
for(int i=0;i<n;i++)
{ memset(v,0,sizeof(v));
if(judge(i))
ans++;
}
cout<<n-ans<<endl;
}
}
另外摘抄网上的一份代码,该代码算然长一点,但是更好理解:
#include<cstdio>
- #include<cstring>
- #include<map>
- #include<cstdlib>
- #include<string>
- using namespace std;
- struct node
- {
- int h,music,sport;
- }man[510],woman[510];
- int T,t,n,m,num_man,num_woman,tot,link[510][510];
- char s[110];
- map<string,int> match;
- bool vis[510];
- int mat[510];
- int getnum()
- {
- int k=match[s];
- if(k!=0)
- return k;
- match[s]=++tot;
- return tot;
- }
- bool dfs(int u)
- {
- int i,j,k;
- for(i=1;i<=num_woman;i++)
- if(link[u][i] && !vis[i])
- {
- vis[i]=1;
- if(mat[i]==0 || dfs(mat[i]))
- {
- mat[i]=u;
- return true;
- }
- }
- return false;
- }
- int main()
- {
- int i,j,k,h,music,sport,ans;
- scanf("%d",&T);
- for(t=1;t<=T;t++)
- {
- scanf("%d",&n);
- num_man=num_woman=tot=0;
- match.clear();
- for(i=1;i<=n;i++)
- {
- scanf("%d",&h);
- scanf("%s",s);
- if(s[0]=='M')
- k=0;
- else
- k=1;
- scanf("%s",s);music=getnum();
- scanf("%s",s);sport=getnum();
- if(k==0)
- {
- num_man++;
- man[num_man].h=h;
- man[num_man].music=music;
- man[num_man].sport=sport;
- }
- else
- {
- num_woman++;
- woman[num_woman].h=h;
- woman[num_woman].music=music;
- woman[num_woman].sport=sport;
- }
- }
- memset(link,0,sizeof(link));
- for(i=1;i<=num_man;i++)
- for(j=1;j<=num_woman;j++)
- if(abs(man[i].h-woman[j].h)>40 || man[i].music!=woman[j].music || man[i].sport==woman[j].sport)
- link[i][j]=0;
- else
- link[i][j]=1;
- ans=0;
- memset(mat,0,sizeof(mat));
- for(i=1;i<=num_man;i++)
- {
- memset(vis,0,sizeof(vis));
- if(dfs(i))
- ans++;
- }
- printf("%d\n",n-ans);
- }
- }
PS:求解最大独立集两种方法,本题使用二分图匹配法,另外是应用最大团(最大团中顶点数量 = 补图的最大独立集中顶点数量)POJ1419即该法的直接应用,而且该题无法运用二分图匹配法。