POJ 3692 Kindergarten

大意不在赘述。

思路:我自己想也想了1、2个小时,后来发现是求图的最大团问题,但是不知道怎么去求解,主要是连边不好连,还有不存在有效的算法,后来我突然发现可以建立原图的补图,于是大概思路也就出来了。

整理一下思路:

1、将男孩,女孩看做顶点,认知关系看做边,那么就是一个最大团问题,NP问题,至今无多项式解法。

2、本题一个附加条件:男生、女生之间相互认识,由于男生、女生相互认识,如果根据认知连边违反了二分图的定义。

3、于是根据2,我们转换一下思路,建立原图的补图,那么最大独立集元素个数等价于原图中最大完全子图(最大团)的顶点数。

4、在二分图中:有公式 最大独立集 = 顶点数-最大二分匹配。

至此, 答案也就出来了。

CODE:

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <map>
using namespace std;

const int MAXN = 210;

int nx, ny, m;
int xlink[MAXN], ylink[MAXN];
int G[MAXN][MAXN];
bool vis[MAXN], flag[MAXN][MAXN];

void init()
{
	memset(G, 0, sizeof(G));
	memset(xlink, -1, sizeof(xlink));
	memset(ylink, -1, sizeof(ylink));
	memset(flag, 0, sizeof(flag));
}

bool ED(int u)
{
	for(int v = 1; v <= ny; v++) if(G[u][v])
	{
		if(!vis[v])
		{
			vis[v] = 1;
			if(ylink[v] == -1 || ED(ylink[v]))
			{
				xlink[u] = v; ylink[v] = u;
				return true;
			}
		}
	}
	return false;
}

void solve()
{
	int ans = 0;
	for(int i = 1; i <= nx; i++)
	{
		if(xlink[i] == -1)
		{
			memset(vis, 0, sizeof(vis));
			ans += ED(i);
		}
	}
	printf("%d\n", nx+ny-ans);
}

int main()
{
	int times = 0;
	while(scanf("%d%d%d", &nx, &ny, &m) && (nx || ny || m))
	{
		init();
		while(m--)
		{
			int u, v;
			scanf("%d%d", &u, &v);
			G[u][v] = 1;
			flag[u][v] = 1;
		}
		for(int i = 1; i <= nx; i++)
		{
			for(int j = 1; j <= ny; j++)
			{
				if(G[i][j] && flag[i][j])
				{
					G[i][j] = 0;
				}
				if(!G[i][j] && !flag[i][j])
				{
					G[i][j] = 1;
				}
			}
		}
		printf("Case %d: ", ++times);
		solve();
	}
	return 0;
}


你可能感兴趣的:(POJ 3692 Kindergarten)