BZOJ 1443 [JSOI2009]游戏Game | UVALive 5882 Racing Car Trail
2016-06-22 23:21
387 查看
题目:
http://www.lydsy.com/JudgeOnline/problem.php?id=1443
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3893
题意:
有一个N×M的棋盘,其中一些格子有障碍,现在有两个人玩游戏,棋盘上有一个棋子,每个人轮流移动棋子,但是不能移动到障碍,也不能移动到之前走过的格子,不能移动的人输,对于每个可能的起点,计算先手是否存在必胜策略。
N,M≤100
题解:
对棋盘中可以互相到达的点之间连边,可以得到一个二分图。
对于二分图,有一个性质是最大匹配数等于最小顶点覆盖数。
最大匹配数是指,选出尽量多的边,使得任意选出的两条边不共用顶点。
最小顶点覆盖是指,选出尽量少的点,使得图中任意一个点要么被选,要么与一个被选的点相连。
证明方法也很简单
最大匹配的每条边各选出一个点,即可覆盖最大匹配中的每个点,如果存在一个点没被覆盖,那么这个点与相连的点能产生一个更大的匹配,因此,每个点至少和一个在匹配里的点相连,|最小点覆盖|≤|最大匹配|。
最大匹配的顶点互不相同,每个匹配里至少要选出一个点才能覆盖所有的匹配,因此|最小点覆盖|≥|最大匹配|。
综上所述,|最小点覆盖|=|最大匹配|。
通过证明过程也可以看出,如果先手从一个一定在最大匹配里的点出发,则一定可以走到一个可能不在最大匹配里的点,反之则可能走不到。
通过这一点就可以确定先手必胜的条件是起点一定在最大匹配中,否则只需要起点是可能不在最大匹配里的点,先手若能移动,后手总能移动到一个在最大匹配里的点。
考虑交替增广路的过程,先求出一个最大匹配,如果一个不在最大匹配里的点可以通过交替增广路变成一个最大匹配里的点,则那个被剥夺匹配的点也不一定在最大匹配中,这个过程可以利用最大流来轻松实现。
考虑将点分为
考虑残量网络,
所以计算完最大匹配后,dfs一下就好了,时间复杂度O((nm)1.5)。
代码:
http://www.lydsy.com/JudgeOnline/problem.php?id=1443
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3893
题意:
有一个N×M的棋盘,其中一些格子有障碍,现在有两个人玩游戏,棋盘上有一个棋子,每个人轮流移动棋子,但是不能移动到障碍,也不能移动到之前走过的格子,不能移动的人输,对于每个可能的起点,计算先手是否存在必胜策略。
N,M≤100
题解:
对棋盘中可以互相到达的点之间连边,可以得到一个二分图。
对于二分图,有一个性质是最大匹配数等于最小顶点覆盖数。
最大匹配数是指,选出尽量多的边,使得任意选出的两条边不共用顶点。
最小顶点覆盖是指,选出尽量少的点,使得图中任意一个点要么被选,要么与一个被选的点相连。
证明方法也很简单
最大匹配的每条边各选出一个点,即可覆盖最大匹配中的每个点,如果存在一个点没被覆盖,那么这个点与相连的点能产生一个更大的匹配,因此,每个点至少和一个在匹配里的点相连,|最小点覆盖|≤|最大匹配|。
最大匹配的顶点互不相同,每个匹配里至少要选出一个点才能覆盖所有的匹配,因此|最小点覆盖|≥|最大匹配|。
综上所述,|最小点覆盖|=|最大匹配|。
通过证明过程也可以看出,如果先手从一个一定在最大匹配里的点出发,则一定可以走到一个可能不在最大匹配里的点,反之则可能走不到。
通过这一点就可以确定先手必胜的条件是起点一定在最大匹配中,否则只需要起点是可能不在最大匹配里的点,先手若能移动,后手总能移动到一个在最大匹配里的点。
考虑交替增广路的过程,先求出一个最大匹配,如果一个不在最大匹配里的点可以通过交替增广路变成一个最大匹配里的点,则那个被剥夺匹配的点也不一定在最大匹配中,这个过程可以利用最大流来轻松实现。
考虑将点分为
X集和
Y集,
源点向
X集的点连边,
X集向
Y集的点连边,
Y集向
汇点连边,边的容量均为1。显然,如果最大匹配是完美匹配,则所有点都是先手必胜的。实际上,我们只需要找出后手必胜的点是哪些即可。
考虑残量网络,
源点能直接到达的
X集的点,是不在最大匹配里的点,这些点通过走
Y集的点回到
X集的点,路径构成一条交替增广路,则回到的
X集的点也可以不在最大匹配里;
汇点能反向到达的
Y集的点,是不在最大匹配里的点,这些点通过反向走
X集的点回到
Y集的点,反向路径构成一条交替增广路,则回到的
Y集的点也可以不在最大匹配里。
所以计算完最大匹配后,dfs一下就好了,时间复杂度O((nm)1.5)。
代码:
#include <cstdio> #include <cstring> #include <algorithm> const int maxs = 101, maxn = maxs * maxs, maxm = maxn * 3; int n, m, N, M, S, T, lnk[maxn], level[maxn], que[maxn], L, R; char str[maxs][maxs]; struct Edge { int nxt, v, f; } e[maxm << 1]; inline int tidx(int x, int y) { return x * m + y; } inline void ridx(int o, int &x, int &y) { x = o / m; y = o % m; } void addEdge(int u, int v, int c) { e[M] = (Edge){lnk[u], v, c}; lnk[u] = M++; e[M] = (Edge){lnk[v], u, 0}; lnk[v] = M++; } bool bfs() { L = R = 0; memset(level, 0, N * sizeof(int)); level[S] = 1; que[R++] = S; while(L < R) { int u = que[L++]; for(int it = lnk[u]; it != -1; it = e[it].nxt) if(e[it].f && !level[e[it].v]) { level[e[it].v] = level[u] + 1; que[R++] = e[it].v; } } return level[T]; } int dfs(int u, int lim) { if(u == T || !lim) return lim; int ret = 0; for(int it = lnk[u], tmp; it != -1; it = e[it].nxt) if(e[it].f && level[e[it].v] == level[u] + 1 && (tmp = dfs(e[it].v, std::min(e[it].f, lim - ret)))) { e[it].f -= tmp; e[it ^ 1].f += tmp; ret += tmp; } if(!ret) level[u] = 0; return ret; } bool vis[maxn]; void check(int u, int o) { vis[u] = 1; if(u < n * m) { int x, y; ridx(u, x, y); if(((x & 1) ^ (y & 1)) == o) str[x][y] = '*'; } for(int it = lnk[u]; it != -1; it = e[it].nxt) if(e[it ^ o].f && !vis[e[it].v]) check(e[it].v, o); } int main() { int cL = 0, cR = 0, flow = 0; scanf("%d%d", &n, &m); N = n * m + 2; M = 0; S = N - 2; T = N - 1; memset(lnk, -1, N * sizeof(int)); for(int i = 0; i < n; ++i) { scanf("%s", str[i]); for(int j = 0; j < m; ++j) { if(str[i][j] == '#') continue; if((i & 1) == (j & 1)) { ++cL; addEdge(S, tidx(i, j), 1); if(i > 0 && str[i - 1][j] != '#') addEdge(tidx(i, j), tidx(i - 1, j), 1); if(j > 0 && str[i][j - 1] != '#') addEdge(tidx(i, j), tidx(i, j - 1), 1); } else { ++cR; addEdge(tidx(i, j), T, 1); if(i > 0 && str[i - 1][j] != '#') addEdge(tidx(i - 1, j), tidx(i, j), 1); if(j > 0 && str[i][j - 1] != '#') addEdge(tidx(i, j - 1), tidx(i, j), 1); } } } while(bfs()) for(int tmp; tmp = dfs(S, maxn); flow += tmp); if(flow == cL && flow == cR) { puts("LOSE"); return 0; } check(S, 0); memset(vis, 0, N * sizeof(bool)); check(T, 1); puts("WIN"); for(int i = 0; i < n; ++i) for(int j = 0; j < m; ++j) if(str[i][j] == '*') printf("%d %d\n", i + 1, j + 1); return 0; }
相关文章推荐
- Poj2638 网络流+最短路+二分答案
- BZOJ3275 Number (最小割)
- [笔记] 网络流-最大流 POJ-1273\HDU-4240
- 上下界网络流初探
- Edmonds-Karp 最大流 hdu 1532 Drained Ditches
- 网络流_poj1273
- POJ 1273 Drainage Ditches 最大流 dinic
- Bad Horse - Practice Round China New Grad Test 2014 - BFS - 二分图判定
- POJ1273-Drainage Ditches
- hdu 1281 二分图匹配求匹配边以及增广链
- 二分图不带权匹配
- 【网络流】复杂的大门
- ACM/ICPC World Finals 2013 C Surely You Congest
- 北京集训队 2016 Day4 alarm
- 网络流算法整理
- 网络流最大流之SAP算法 详解
- [BZOJ1797][AHOI2009][最大流][强连通分量]Mincut最小割
- [BZOJ2324][ZJOI2011][最小费用最大流]营救皮卡丘
- [BZOJ1834][ZJOI2010][最大流][最小费用最大流]网络扩容
- Codeforce 85E (二分答案+二分图染色)