UVa 10505 - Montesco vs Capuleto

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mobius_strip/article/details/87545303

题目

有N个人要参加宴会,他们之间有些人有敌对关系,敌对关系是对称的,而且可以传递(敌人的敌人是朋友)。求最多可以邀请多少人。

分析

图论,二分图匹配。将人们的关系分成四种:0没有关系,-1敌对关系,1朋友关系(敌人的敌人是朋友-1*-1 = 1),2矛盾关系(即使朋友又是敌人,如第三组数据);可以利用乘法来传递关系。将矛盾的人全部删除(通过传递可以得到他们是自己的敌人),然后求最小覆盖(等于最大匹配),N - 最小覆盖即使结果。

说明

ε=(´ο`*)))唉。。。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int relation[202][202];
int used[202], link[202];

// Bipartite graph matching
int dfs(int s, int n)
{
	for (int i = 1 ; i <= n; ++ i) {
    	if (relation[s][i] == -1 && !used[i]) {
    		used[i] = 1;
        	if (link[i] == -1 || dfs(link[i], n)) {
            	link[i] = s;
            	link[s] = i;
            	return 1;
			}
    	}
    }
    return 0;
}

int main()
{
	int M, N, p, enemy;
	while (~scanf("%d", &M)) 
	while (M --) {
		scanf("%d", &N);
		for (int i = 1; i <= N; ++ i) {
			for (int j = 1; j <= N; ++ j) {
				relation[i][j] = 0;
			}
	    	link[i] = -1;
		}
		for (int i = 1; i <= N; ++ i) {
			scanf("%d", &p);
			for (int j = 1; j <= p; ++ j) {
				scanf("%d", &enemy);
				relation[i][enemy] = -1;
				relation[enemy][i] = -1;
			}
		}
		// Delete the contradiction nodes
		for (int k = 1; k <= N; ++ k) {
			for (int i = 1; i <= N; ++ i) {
				for (int j = 1; j <= N; ++ j) {
					int new_relation = relation[i][k] * relation[k][j];
					if (new_relation) {
						if (relation[i][j] == 0) {
							relation[i][j] = relation[i][k] * relation[k][j];
						}else if (relation[i][j] != new_relation || 
								new_relation == 2 || new_relation == -2) {
							relation[i][j] = 2;
							link[i] = -2;
						}
					}
				}
			}
		}
		
		int sum = 0;
	    for(int i = 1 ; i <= N ; ++ i) {
			if (link[i] == -2) sum += 1;
			if (link[i] != -1) continue;
			for (int j = 1; j <= N; ++ j) {
				used[j] = 0;
			}
		    sum += dfs(i, N);
		}
    	
    	printf("%d\n", N - sum);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/mobius_strip/article/details/87545303
VS