首先先理清楚一下这题的关系,每一个人要么是学校里的学生,要么不是。而是学校里学生,要么回家了,要么没回家。那么可以提供床位的,就是学校的在校学生,而需要床位的,就是不是这个学校的学生的人,和在学校没回家的在校学生。一个人占一张床,而在校学生自己可以睡自己的床,因此我们把所有的人分成两部分,需要床的和提供床的,在校学生不回家的两边都有(建一条自己到自己的边),根据认识关系建边,因此我们得到了二分图,而我们所需要的睡尽可能多的人,因此就是求二分图的最大匹配
因此大概有两个算法可以求解
- 匈牙利算法求最大匹配
最大匹配算法,如果当前的点可以只通过一条边找到匹配点,那么就直接把这个点匹配上,如果当前点连接的所有点都被匹配过了,那么我们就继续dfs寻找之前连接过的点能不能找到新的点来连接,然后腾出一个未被匹配的和当前点连接的点来和当前点匹配。
每个点都返回是否能匹配上,记录匹配数,输出即可
代码如下
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100;
int school[maxn];
int home[maxn];
int head[maxn];
int vis[maxn],match[maxn];
int tot,n;
struct _edge {int to,nex; }edge[maxn*maxn];
void add(int u,int v){
edge[tot] = (_edge){v,head[u]};
head[u] = tot++;
}
bool dfs(int u){
for (int i=head[u]; ~i; i=edge[i].nex) {
int v = edge[i].to;
if (!vis[v]){
vis[v] = 1;
if (!match[v] || dfs(match[v])){
match[v] = u;
return true;
}
}
}
return false;
}
void init(){
tot = 0;
memset(head, -1, sizeof(head));
memset(match, 0, sizeof(match));
}
int main(){
// freopen("/Users/chutong/data.txt", "r", stdin);
int T,rel;
scanf("%d",&T);
while (T--) {
scanf("%d",&n); tot = 0; init();
for (int i=1; i<=n; i++)
scanf("%d",&school[i]);
for (int i=1; i<=n; i++) {
scanf("%d",&home[i]);
if (!home[i] && school[i]) add(i, i);
}
for (int i=1; i<=n; i++) {
for (int j=1; j<=n; j++) {
scanf("%d",&rel);
if (rel && school[j]){
add(i, j);
}
}
}
int sum = 0;
for (int i=1; i<=n; i++) {
if ((school[i] && !home[i]) || !school[i]){
memset(vis, 0, sizeof(vis));
if (dfs(i)) sum--;
sum++ ;
}
}
if (sum) cout<<"T_T"<<endl;
else cout<<"^_^"<<endl;
}
return 0;
}
- 网络流最大流
建立一个超级原点s连接所有提供床位的点和一个超级汇点t连接所有需要床位的点,我们将每条边的权记录为1,那么跑网络流算法,求出最大流量即可。
代码如下
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6;
struct _edge { int to, nex, c, f; } edge[maxn];
int head[maxn],dep[maxn];
int n,m,s,t,tot;
int bfs() {
memset(dep, 0, sizeof(dep));
queue<int> q; q.push(s);
dep[s] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = head[u]; ~i; i = edge[i].nex) {
int v = edge[i].to;
if(!dep[v] && edge[i].c > edge[i].f) {
dep[v] = dep[u] + 1; q.push(v);
}
}
}
if (dep[t] != 0) return 1;
else return 0;
}
int dfs(int u, int capflow) {
if (u == t) return capflow;
int addflow = 0;
for(int i = head[u]; i != -1 && addflow < capflow; i = edge[i].nex){
int v = edge[i].to;
if(dep[u]+1 == dep[v] && edge[i].c > edge[i].f) {
int nowflow = dfs(v, min(capflow-addflow, edge[i].c-edge[i].f));
edge[i].f += nowflow;
edge[i^1].f -= nowflow;
addflow += nowflow;
}
}
return addflow;
}
int dinic() {
int maxflow = 0;
while(bfs()) maxflow += dfs(s, INT_MAX);
return maxflow;
}
void add(int u, int v, int c) {
edge[tot] = (_edge){v,head[u],c,0};
head[u] = tot++;
edge[tot] = (_edge){u,head[v],0,0};
head[v] = tot++;
}
void init(){
memset(dep, 0, sizeof(dep));
memset(edge, 0, sizeof(edge));
memset(head, -1, sizeof(head));
tot = 0;
}
int school[maxn],home[maxn];
int rel[105][105];
int main() {
// freopen("/Users/chutong/data.txt", "r", stdin);
int T;
scanf("%d",&T);
while (T--) {
init();
scanf("%d",&n);
s = 0; t = n*2 + 1;
for (int i=1; i<=n; i++){
scanf("%d",&school[i]);
if (school[i]) add(i+n, t, 1);
}
int res = 0;
for (int i=1; i<=n; i++){
scanf("%d",&home[i]);
if ((school[i] && !home[i]) || !school[i]){
add(s, i, 1); res++;
}
}
for (int i=1; i<=n; i++){
for (int j=1; j<=n; j++){
scanf("%d",&rel[i][j]);
if (rel[i][j] || i == j) {
add(i, j+n, 1);
}
}
}
int ans = dinic();
if (ans >= res) printf("^_^\n");
else printf("T_T\n");
}
return 0;
}