NOI模拟:保镖(Hall定理)
来源:互联网 发布:剑灵灵族捏脸数据截图 编辑:程序博客网 时间:2024/04/29 22:25
题意:
给一个二分图,找出满足以下条件的点集的个数:
1.该点集是原点集的子集。
2.该点集是一个匹配的点集的子集。
(n ≤ 20)
题解:
首先任意匹配的点集一定是一个最大匹配的子集。
题意转化为找出是最大匹配的子集的点集个数。
由Hall定理,对于一边的点而言,如果一个点集的任意子集满足在一个最大匹配中,而且这个点集满足连接的点≥这个点集的大小,那么这个点集一定在最大匹配中。
同理,对于两边的点而言,一样满足:
把两边选出的点染色,并选出两边的点连出的边,不难发现这些边最终会组成环和链,对于一个环,两两匹配即可,对于一条链,首尾依次匹配即可。
#include <bits/stdc++.h>using namespace std;const int Maxn = 2e6 + 50;int n, m, wa[25], wb[25], t, lima, limb, vala[Maxn], cnta, valb[Maxn], cntb, status[2][25];bool isa[Maxn], isb[Maxn];char ch[25][25];inline int findpos(int x){ int l = 1, r = cntb, ans = 0; while (l <= r) { int mid = (l + r) >> 1; if (valb[mid] >= x) ans = (cntb - mid + 1), r = mid - 1; else l = mid + 1; } return ans;}inline int check(int lim, int x){ int res = 0; for (int j = 0; j < lim; j++) { if (x & (1 << j)) ++res; } return res;}int main(){ freopen("lx.in", "r", stdin); scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) { scanf("%s", ch[i]); for (int j = 0; j < m; j++) { if (ch[i][j] == '1') { status[0][i] |= (1 << j); status[1][j] |= (1 << i); } } } for (int i = 0; i < n; i++) { scanf("%d", &wa[i]); for (int j = 0; j < m; j++) if (ch[i][j] == '1') { isa[(1 << i)] = 1; break; } } for (int i = 0; i < m; i++) { scanf("%d", &wb[i]); for (int j = 0; j < n; j++) if (ch[j][i] == '1') { isb[(1 << i)] = 1; break; } } scanf("%d", &t); lima = (1 << n) - 1; limb = (1 << m) - 1; for (int i = 1; i <= lima; i++) { int sum = 0, cnt = 0, bz = 1, Status = 0; for (int j = 0; j < n; j++) { if (i & (1 << j)) { ++cnt; Status |= status[0][j]; if (!isa[i ^ (1 << j)]) bz = 0; sum += wa[j]; } } if (cnt == 1 && isa[i]) vala[++cnta] = sum; if (cnt > 1 && cnt <= m && bz && check(m, Status) >= cnt) vala[++cnta] = sum, isa[i] = 1; } for (int i = 1; i <= limb; i++) { int sum = 0, cnt = 0, bz = 1, Status = 0; for (int j = 0; j < m; j++) { if (i & (1 << j)) { ++cnt; Status |= status[1][j]; if (!isb[i ^ (1 << j)]) bz = 0; sum += wb[j]; } } if (cnt == 1 && isb[i]) valb[++cntb] = sum; if (cnt > 1 && cnt <= n && bz && check(n, Status) >= cnt) valb[++cntb] = sum, isb[i] = 1; } vala[++cnta] = 0; valb[++cntb] = 0; sort(valb + 1, valb + cntb + 1); long long ans = 0; for (int i = 1; i <= cnta; ++i) { ans += findpos(t - vala[i]); } printf("%lld\n", ans);}
阅读全文
0 0
- NOI模拟:保镖(Hall定理)
- jzoj 5000. 【NOI2017模拟3.4】保镖 hall定理+搜索
- 保镖(hall定理&&集合动规&&优化)
- BZOJ3693:圆桌会议(Hall定理)
- HALL定理
- Hall定理(bzoj 1135: [POI2009]Lyz)
- Hall定理学习小记
- LOJ 6062 [Hall定理]
- Hall定理(二分图匹配问题,Hungary算法基础)
- Monty Hall问题 模拟
- NOI 模拟试题(一)
- NOI 模拟试题(二)
- NOI 模拟试题(三)
- 保镖
- HDOJ City hall 1453(模拟)
- Educational Codeforces Round 8 F. Bear and Fair Set(最大流 | Hall定理)
- Educational Codeforces Round 8 F. Bear and Fair Set(最大流 | Hall定理)★
- BZOJ 2138: stone Hall定理 线段树
- SSH命令与ssh免密登陆
- luoguP2709 小B的询问
- 2017 ACM/ICPC Asia Regional Shenyang Online
- Shiro过滤器过滤属性含义
- Servlet的页面跳转方式
- NOI模拟:保镖(Hall定理)
- java线程池
- Hive内表和外表的区别
- Weblogic10部署Web项目
- “玲珑杯” 线上赛 Round #5 Variance(线段树)
- 20170910WindowsPrj07_内存映射
- Linux下tar.xz结尾的文件的解压方法
- [C++学生类] The Student Class
- 数学建模(15)——聚类分析