二分图求最大独立集。题意:Frank是一个思想保守的老师。有一次他需要带一些学生出去旅行,但是又怕其中一些学生在旅途中萌生爱意。为了降低这种事情的发生概率,他决定确保带出去的任意两个学生至少要满足下面4个条件中的一条:
1.身高相差要大于40厘米
2.性别相同
3.最喜欢的音乐类型不同
4.最喜欢的体育比赛相同(因为他们很可能是不同的球队的球迷,这样他们就可能聊得很不愉快)
现在的任务是帮助Frank挑选尽量多的学生,使得任意两个学生至少满足上述条件中的一条。
我的解题思路:因为人的性别只有男女两种,所以这里就有两种不同的点集,为二分图的构建奠定了基础,因为性别相同的两个人是不可能互相产生爱意的(不要跟我讨论同性恋问题-_-||)。题意是如果两个学生之间满足上述4个条件中的一个,那么这两个学生是不可能产生爱意的。那么两个学生产生爱意的唯一可能是上述四个条件都不满足,如果两个学生能够产生爱意,那么可以给这两个学生连一条无向边。这样,二分图就构建完毕,最后题目要求确保带出去的学生任意两个都不能产生爱意,即任意两个学生之间都没有连一条边,而且要求带出去的学生尽量多,这正是二分图求最大独立集的性质。根据二分图最大独立集等于二分图点数减去最大匹配数可得答案。
我的解题代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define N 505
#define M 101
struct student //定义学生信息结构体
{
int height; //身高
bool man; //是否为男性
char music[M]; //最喜欢的音乐类型
char sport[M]; //最喜欢的体育比赛的类型
};
int match[N];
bool vis[N];
vector <int> e[N];
student node[N]; //存储每个学生的信息
int t, n;
void InitRead();
void DataProcess();
bool Dfs(int x);
int main()
{
scanf("%d", &t);
while (t--)
{
InitRead();
DataProcess();
}
return 0;
}
void InitRead()
{
memset(match, -1, sizeof(match));
char sex;
scanf("%d", &n);
for (int i=0; i<n; ++i) //输入学生信息顺便初始化邻接表
{
e[i].clear();
scanf("%d", &node[i].height);
scanf(" %c", &sex);
node[i].man = sex == 'M' ? true : false;
scanf("%s %s", node[i].music, node[i].sport);
}
for (int i=0; i<n; ++i) //开始准备建边
{
for (int j=i+1; j<n; ++j)
{
if (node[i].man == node[j].man) continue;
if (abs(node[i].height - node[j].height) > 40) continue;
if (strcmp(node[i].music, node[j].music) != 0) continue;
if (strcmp(node[i].sport, node[j].sport) == 0) continue;
//到达这里说明四个条件都没有满足,可能萌生爱意,接下来建无向边
e[i].push_back(j);
e[j].push_back(i);
}
}
return;
}
void DataProcess()
{
int ans = 0;
for (int i=0; i<n; ++i)
{
memset(vis, false, sizeof(vis));
if (Dfs(i)) ans++;
}
printf("%d\n", n - ans / 2);
return;
}
bool Dfs(int x)
{
int size = e[x].size();
for (int i=0; i<size; ++i)
{
if (!vis[e[x][i]])
{
vis[e[x][i]] = true;
if (match[e[x][i]] == -1 || Dfs(match[e[x][i]]))
{
match[e[x][i]] = x;
return true;
}
}
}
return false;
}