P2055 [ZJOI2009]假期的宿舍 - 二分图最大匹配

把人和床分开考虑,题目说每个人只能睡和自己直接认识的人的床,就是一种边的关系,但是并不是人与人,实际上人与人之间连边是很难处理的,但是如果把人和床连边,就是一张二分图,左右两边分别是不同的东西,然后求一下最大匹配就好了
没思路的时候换换角度,看能不能搞出什么“新东西”来
注意多组数据不超时的情况下能用memset尽量用,有时候感觉某个数组可以不清空但实际上是需要清空的
还有注意连边的时候没那么简单。。。看注释吧

#include 
#include 
#include 
#include 
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 210;

int n,m,match[MAXN],ans,edge_tot,tot,outnum,last[MAXN],vis[MAXN],gra[MAXN][MAXN],house[MAXN]; 
int sch[MAXN],t,bad[MAXN];

struct Edge{
	int u,v,to;
	Edge(){}
	Edge(int u, int v, int to) : u(u), v(v), to(to) {}
}e[10010];

inline void add(int u, int v) {
	e[++edge_tot] = Edge(u, v, last[u]);
	last[u] = edge_tot;
}

bool dfs(int x) {
	for(int i=last[x]; i; i=e[i].to) {
		int v = e[i].v;
		if(vis[v]) continue;
		vis[v] = 1;
		if(!match[v] || dfs(match[v])) {
			match[v] = x;
			return true;
		}
	}
	return false;
}

int main() {
	scanf("%d", &t);
	while(t--) {
		
		ans = 0, edge_tot = 0, outnum = 0;
		memset(match, 0, sizeof(match));
		memset(last, 0, sizeof(last));
		memset(house, 0, sizeof(house));
		memset(sch, 0, sizeof(sch));
		
		scanf("%d", &n);
		for(int i=1; i<=n; i++) {
			scanf("%d", &sch[i]);
		}
		for(int i=1; i<=n; i++) {
			int temp_sca = 0;
			if(sch[i] == 1) scanf("%d", &house[i]);
			else scanf("%d", &temp_sca), outnum++;
			if(!house[i] && sch[i]) {//和自己的床连边,首先i得有床,其次得不回家
				outnum++;
				add(i, i+n);
				add(i+n, i);
			}
		}
		for(int i=1; i<=n; i++) {
			for(int j=1; j<=n; j++) {
				scanf("%d", &gra[i][j]);
				if(gra[i][j] && sch[j] && house[i] == 0) {
					add(i, j+n);//i这个人和j的床位连边,需要i不是回家的人并且j是有床的(j不一定必须回家)
					add(j+n, i);
				}
			}
		}
		for(int i=1; i<=n; i++) {
			if(!house[i]) {
				memset(vis, 0, sizeof(vis));
				if(dfs(i)) ans++;
			}
		}
		if(ans == outnum) {
			printf("^_^\n");
		} else printf("T_T\n");
	}
	return 0;
} 

你可能感兴趣的:(NOIP,图论,二分图)