POJ2771 Guardian of Decency 保守的老师(NWERC2005)

传送


题面:有(n)个学生,每个学生有4个属性:身高,性别,最喜欢的音乐,最喜欢的体育比赛。选择尽量多的学生,满足下面4条中的至少一条:
(1)身高相差至少40厘米(不包含40)。
(2)性别相同。
(3)最喜欢的音乐属于不同类型。
(4)最喜欢的体育比赛相同。


这题也是一道二分图的典型例题,得做一遍才能形成这个思想。


首先我么按性别将所有点分成左右两部分。接下来如果左右两点间剩下三个条件都不满足,就连一条边。
那么我们要求的就是选尽量多的点,使选择的任意两个点之间没有边,即二分图的最大独立集。
最大独立集=总点数-最大匹配数。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<queue>
#include<assert.h>
#include<ctime>
using namespace std;
#define enter puts("") 
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
#define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 505;
const int maxe = 3e5 + 5;
In ll read()
{
	ll ans = 0;
	char ch = getchar(), las = ' ';
	while(!isdigit(ch)) las = ch, ch = getchar();
	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
	if(las == '-') ans = -ans;
	return ans;
}
In void write(ll x)
{
	if(x < 0) x = -x, putchar('-');
	if(x >= 10) write(x / 10);
	putchar(x % 10 + '0');
}
In void MYFILE()
{
#ifndef mrclr
	freopen(".in", "r", stdin);
	freopen(".out", "w", stdout);
#endif
}

int n;
struct Stu
{
	int h; string sex, mus, spo;
};
vector<Stu> M, F;

In bool check(Stu& a, Stu& b)
{
	return abs(a.h - b.h) <= 40 && a.mus == b.mus && a.spo != b.spo;
}

struct Edge
{
	int nxt, to;
}e[maxe];
int head[maxn], ecnt = -1;
In void addEdge(int x, int y)
{
	e[++ecnt] = (Edge){head[x], y};
	head[x] = ecnt;
}

bool vis[maxn];
int lft[maxn];
In bool dfs(int now)
{
	forE(i, now, v)			//去看宏定义,改了一点! 
		if(!vis[v])
		{
			vis[v] = 1;
			if(lft[v] == -1 || dfs(lft[v])) {lft[v] = now; return 1;}
		}
	return 0;
}

In int hung()
{
	int ret = 0; Mem(lft, -1);
	for(int i = 0; i < (int)M.size(); ++i)
	{
		Mem(vis, 0);
		if(dfs(i + 1)) ++ret;
	}
	return ret;
}

In void init()
{
	M.clear(), F.clear();
	Mem(head, -1), ecnt = -1;
}

int main()
{ 
	int T = read();
	while(T--)
	{
		init();
		n = read(); Stu tp;
		for(int i = 1; i <= n; ++i)
		{
			tp.h = read();
			cin >> tp.sex >> tp.mus >> tp.spo;
			tp.sex[0] == 'M' ?  M.push_back(tp) : F.push_back(tp);
		}
		for(int i = 0; i < (int)M.size(); ++i)
			for(int j = 0; j < (int)F.size(); ++j)
				if(check(M[i], F[j])) addEdge(i + 1, j + 1);
		write(n - hung()), enter; 
	}
	return 0;
}
原文地址:https://www.cnblogs.com/mrclr/p/14775967.html