bzoj1433_最大流|二分图最大匹配
来源:互联网 发布:88端口怎么起 编辑:程序博客网 时间:2024/05/16 05:34
调了一下午的网络流, 最后发现是因为想要用0作为下标而遍历的时候还是用习惯性的写法, 简直不开心。
网络流的题目基本都是重点在建模上, 我们来看看这一题怎么建模: 首先, 学生人数和可用床数是确定的, 我们就自己创造一个源点和一个汇点。 考虑到学生必须全部有床睡, 那么从原点出发流到床再流到学生即可。 这时我们能够机智的发现一件事, 其实就是求一个二分图的最大匹配, 愤愤然地感觉自己被坑了。 最终只要看匹配数是否等于有需求的学生数即可。
另一件事就是判断有需求的学生, 只要是外来的或校内但不回家的就是有需求的。
#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#include <cstdlib>#define N 200#define M 20000#define INF 10000000using namespace std;struct edge{ int to, next;}e[M];int t, n, num, ans, cont;int a[N], b[N], p[N], mat[N], flag[N];void add(int x, int y){ e[num].to = y; e[num].next = p[x]; p[x] = num++;}void clean(){ ans = num = cont = 0; memset(p, -1, sizeof p); memset(e, 0, sizeof e); memset(mat, 0, sizeof mat);}void init(){ clean(); int x; scanf("%d", &n); t = n << 1 | 1; for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); for (int i = 1; i <= n; ++i) scanf("%d", &b[i]); for (int i = 1; i <= n; ++i) if (!a[i] || (a[i] && !b[i])) ++cont; for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) { scanf("%d", &x); if (((i == j && a[i]) || (x && a[j])) && (!a[i] || (a[i] && !b[i]))) { add(j+n, i); add(i, j+n); } }}bool find(int x){ for (int i = p[x]; i != -1; i = e[i].next) { int k = e[i].to; if (!flag[k]) { flag[k] = 1; if (!mat[k] || find(mat[k])) { mat[k] = x; return true; } } } return false;}void deal(){ for (int i = 1; i <= n; ++i) { memset(flag, 0, sizeof flag); ans += find(i); } if (ans == cont) printf("^_^\n"); else printf("T_T\n");}int main(){ freopen("a.in", "r", stdin); int T; scanf("%d", &T); while(T--) { init(); deal(); } return 0;}//二分图匹配代码
#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#include <cstdlib>#define N 200#define M 20000#define INF 10000000using namespace std;struct edge{ int to, next, cap, flow;}e[M];int t, n, num, ans, cont;int a[N], b[N], p[N], d[N], flag[N], now[N];void add(int x, int y, int z){ e[num].to = y; e[num].next = p[x]; e[num].cap = z; p[x] = num++;}void clean(){ ans = num = cont = 0; memset(p, -1, sizeof p); memset(d, 0, sizeof d); memset(e, 0, sizeof e);}void init(){ clean(); int x; scanf("%d", &n); t = n << 1 | 1; for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); for (int i = 1; i <= n; ++i) scanf("%d", &b[i]); for (int i = 1; i <= n; ++i) if (!a[i] || (a[i] && !b[i])) { add(i, t, 1); add(t, i, 0); ++cont; } for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) { scanf("%d", &x); if (((i == j && a[i]) || (x && a[j])) && (!a[i] || (a[i] && !b[i]))) { add(j+n, i, 1); add(i, j+n, 0); } } for (int i = 1; i <= n; ++i) if (a[i]) { add(0, i+n, 1); add(i+n, 0, 0); }}bool bfs(){ memset(flag, 0, sizeof flag); d[0] = 0, flag[0] = 1; queue<int>q; q.push(0); while(!q.empty()) { int x = q.front(); q.pop(); for (int i = p[x]; i != -1; i = e[i].next) { int k = e[i].to; if (!flag[k] && e[i].cap > e[i].flow) { flag[k] = 1; d[k] = d[x] + 1; q.push(k); } } } for (int i = 0; i <= t; ++i) now[i] = p[i]; return flag[t];}int dfs(int x, int mini){ if (x == t || !mini) return mini; int flow = 0; for (int i = now[x]; i != -1; i = e[i].next) { now[x] = i; int k = e[i].to; if (d[k] == d[x] + 1) { int tmp = dfs(k, min(mini, e[i].cap-e[i].flow)); if (tmp <= 0) continue; e[i].flow += tmp; e[i^1].flow -= tmp; flow += tmp; mini -= tmp; if (!mini) break; } } return flow;}void deal(){ while(bfs()) ans += dfs(0, INF); if (ans == cont) printf("^_^\n"); else printf("T_T\n");}int main(){ freopen("a.in", "r", stdin); freopen("a.out", "w", stdout); int T; scanf("%d", &T); while(T--) { init(); deal(); } return 0;}//网络流代码
0 0
- bzoj1433_最大流|二分图最大匹配
- 二分图最大匹配
- 二分图最大匹配 。
- 二分图最大匹配
- 二分图最大匹配
- 二分图最大匹配
- 二分图最大匹配
- 二分图 最大匹配
- 二分图最大匹配
- 二分图最大匹配
- 二分图最大匹配
- 二分图最大匹配
- 二分图最大匹配
- 二分图最大匹配
- 二分图最大匹配
- 二分图最大匹配
- 二分图最大匹配
- 二分图 最大匹配
- PHP中error_reporting()函数的用法(修改PHP屏蔽错误)
- 你相信吗? 这些照片都是用iPhone拍出来的
- HDU 1234开门人和关门人。
- 模拟退火算法
- 求两个整数的最大公约数和最小公倍数
- bzoj1433_最大流|二分图最大匹配
- OpenDingux 编译
- matlab中的BP神经网络
- C/C++变量命名规范
- 软件测试从零开始
- BZOJ 2157 旅游 树链剖分
- 滑动式界面和消息数视图
- Servlet中filter过滤<dispatcher>FORWARD</dispatcher>标签使用
- glViewport