题意:
学校放假了有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题。比如 A 和 B 都是学校的学生,A 要回家,而 C 来看B,C 与 A 不认识。我们假设每个人只能睡和自己直接认识的人的床。那么一个解决方案就是 B 睡 A 的床而 C 睡 B 的床。而实际情况可能非常复杂,有的人可能认识好多在校学生,在校学生之间也不一定都互相认识。我们已知一共有 n 个人,并且知道其中每个人是不是本校学生,也知道每个本校学生是否回家。问是否存在一个方案使得所有不回家的本校学生和来看他们的其他人都有地方住。
思路:
二分图匹配,建完边后直接dfs,把在学校的认识的连边,把不在学校的和在学校的认识的连边,在学校不回家的自己连自己,然后跑匈牙利把计算的结果和总共要在学校睡觉的人数比较,相等输出^_^否则输出T_T
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e2 + 10;
struct node {
int v, net;
} no[N * 100];
int n, t, h[N], cnt, tot, ans;
int vis[N], march[N], sc[N], home[N];
void add(int u, int v) {
no[cnt] = (node) {
v, h[u]
};
h[u] = cnt++;
}
int dfs(int x) {
for(int i = h[x]; ~i; i = no[i].net) {//x可以连的边
int v = no[i].v;
if(!vis[v]) {//如果没人占
vis[v] = 1;
if(!march[v] || dfs(march[v])) {//如果没匹配或者之前有可以变换匹配的
march[v] = x;
return 1;
}
}
}
return 0;
}
int main() {
cin >> t;
while(t--) {
cin >> n;
cnt = tot = 0, ans = 0;
memset(h, -1, sizeof h);
memset(march, 0, sizeof march);
for(int i = 1; i <= n; i++)
cin >> sc[i];
for(int i = 1; i <= n; i++) {
cin >> home[i];
if(!home[i] && sc[i])//如果不回家并且是在校生
add(i, i);
}
for(int i = 1; i <= n; i++)
if(!sc[i] || (sc[i] && !home[i]))//如果不是在校生或者是不回家的在校生
tot++;
for(int x, i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) {
cin >> x;
if(x && sc[j])//如果认识并且认识的是在校生
add(i, j);
}
for(int i = 1; i <= n; i++)
if((sc[i] && !home[i]) || !sc[i]) {//如果是不回家的在校生或者不是在校生
memset(vis, 0, sizeof vis);
ans += dfs(i);
}
ans == tot ? puts("^_^") : puts("T_T");
}
return 0;
}