POJ 2771 Guardian of Decency (最大独立集Hungary)

本文介绍了一个基于匈牙利算法的学生旅行团成员选择问题。通过构建特定条件下的匹配图,利用Trie树进行字符串特征编码,确保所选学生间不会产生恋爱关系。最终实现了最大化旅行团人数的目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:老师想带他的学生们出去旅行,但是不想他们之间发生恋爱。也就是说,任意两个可能发生恋爱的人不能同时都带去。要求能带去旅行的最大人数。老师认为满足下列情况的人之间不会发生恋爱。
1.Their height differs by more than 40 cm.
2.They are of the same sex. 
3.Their preferred music style is different. 
4.Their favourite sport is the same (they are likely to be fans of different teams and that would result in fighting). 
题解:通过Trie树来给3,4两个条中的字符串编号。建图是关键。

#include <cmath>
#include <iostream>
using namespace std;

#define N 510
bool vis[N];
int bond[N][N], match[N];
int cnt, mark, n;

struct Student
{
	int h, m, s;
	char sex;
} stud[N];

struct Tree  
{  
    int key;  
    Tree *next[30];  
} node[N*2];  


int Insert ( char* word, Tree *location )  
{  
    int i = 0, id;  
    while ( word[i] )  
    {  
		if ( word[i] != '-' )
            id = word[i] - 'a';
		else id = 29;
        if ( location->next[id] == NULL )  
            location->next[id] = &node[++cnt];  
        location = location->next[id];  
        ++i;  
    }  
    if ( location->key == 0 )  
        location->key = ++mark;  //编号
    return location->key;  
}  

bool find_path ( int u )
{
	for ( int i = 1; i <= bond[u][0]; i++ )
	{
		int v = bond[u][i];
		if ( ! vis[v] )
		{
			vis[v] = 1;
			if ( !match[v] || find_path(match[v]) )
			{
				match[v] = u;
				return true;
			}
		}
	}
	return false;
}

int Hungary ()
{
	int ans = 0;
	memset(match,0,sizeof(match));
	for ( int i = 1; i <= n; i++ )
	{
		memset(vis,0,sizeof(vis));
		if ( find_path(i) ) ans++;
	}
	return ans;
}

bool check ( int a, int b )
{
	if ( abs(stud[a].h-stud[b].h) > 40 ) return false;
	if ( stud[a].sex == stud[b].sex ) return false;
	if ( stud[a].m != stud[b].m ) return false;
	if ( stud[a].s == stud[b].s ) return false;
	return true;
}

int main()
{
	char sex;
	char m[110], s[110];
	int t, h, i, j;

	scanf("%d",&t);
	while ( t-- )
	{
		mark = 0;
		cnt = 2;
		memset(bond,0,sizeof(bond));
		memset(node,NULL,sizeof(node));
		memset(stud,0,sizeof(stud));

		scanf("%d",&n);

		for ( i = 1; i <= n; i++ )
		{
			scanf("%d %c %s %s",&h,&sex,&m,&s);
			stud[i].h = h;
			stud[i].sex = sex;
			stud[i].m = Insert(m,&node[0]); // node[0]做为music的根节点
			stud[i].s = Insert(s,&node[1]); // node[1]作为sport的根节点
		}

		for ( i = 1; i <= n; i++ )
		{
			for ( j = 1; j <= n; j++ )
				if ( check ( i, j ) )
				{
					bond[i][0]++;
					bond[i][bond[i][0]] = j;
				}
		}
		printf("%d\n",n-Hungary()/2);
	}
	return 0;
}

			




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值