题目链接:
不懂二分图的可以看看这篇博客:
(5条消息) 二分图及其多个扩展用法详解 + 模板题:算法竞赛进阶指南 关押罪犯 棋盘覆盖 机器任务 骑士放置 捉迷藏_wsh1931的博客-CSDN博客
解题思路:把床和需要床人分为二分图。即需要床的人在二分图左边,床在二分图右边。
存在两种情况:
1:床和在学校且不回家的人连一条边
2:床和不在学校的人且这个人认识床的主人连一条边。
最后判断需要穿的人数是否和已经匹配成功的床的数量相等
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N = 55, M = N * N; int n; bool st[N]; int home[N]; int match[N]; int school[N]; int h[N], e[M], ne[M], idx; void add(int a, int b)//邻接表 { e[idx] = b; ne[idx] = h[a]; h[a] = idx; idx ++ ; } bool find(int x)//二分图模板 { for (int i = h[x]; i != -1; i = ne[i]) { int j = e[i]; if (st[j]) continue; st[j] = true; if (match[j] == -1 || find(match[j])) { match[j] = x; return true; } } return false; } int main() { int T; cin >> T; while (T -- ) { idx = 0; memset(h, -1, sizeof h); memset(match, -1, sizeof match); cin >> n; int sum = 0; for (int i = 1; i <= n; i ++ ) cin >> school[i]; for (int i = 1; i <= n; i ++ ) { cin >> home[i]; if (school[i] && !home[i]) add(i, i);//若他在学校且不回家则自己连一条边 } for (int i = 1; i <= n; i ++ )//统计需要床的人数 if (school[i] && !home[i] || !school[i]) sum ++ ; for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) { int x; cin >> x; if (x == 1 && school[j]) add(i, j);//若i认识j且j是学校的学生则i和j连一条边 } for (int i = 1; i <= n; i ++ )//枚举二分图左边,即需要床的人 if (school[i] && !home[i] || !school[i]) { memset(st, false, sizeof st); if (find(i)) sum -- ;//若这个需要床的人找到了床则需要床的人数减一 } if (!sum) printf("^_^\n"); else printf("T_T\n"); } return 0; }