Bzoj

来源:互联网 发布:linux内网穿透 编辑:程序博客网 时间:2024/06/05 20:59

1443: [JSOI2009]游戏Game

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1245  Solved: 575
[Submit][Status][Discuss]

Description

Input

输入数据首先输入两个整数N,M,表示了迷宫的边长。 接下来N行,每行M个字符,描述了迷宫。

Output

若小AA能够赢得游戏,则输出一行"WIN",然后输出所有可以赢得游戏的起始位置,按行优先顺序输出 每行一个,否则输出一行"LOSE"(不包含引号)。

Sample Input

3 3
.##
...
#.#

Sample Output

WIN
2 3
3 2

HINT

对于100%的数据,有1≤n,m≤100。 对于30%的数据,有1≤n,m≤5。

Source

[Submit][Status][Discuss]

第一道二分图博弈
感觉比想象的要简单
首先你一步我一步就把这个图搞成了一个二分图
我们来分析一下
加入我们能够找到这个图的完美匹配,那么当AA放下棋子之后,YY无论怎么走都要经过匹配边,接着AA走的一定是非匹配边,当走完最后一条匹配边是,AA就输了,所以如果有完美匹配直接输出LOSE
反之,如果没有完美匹配,那么一定有非匹配点
AA在非匹配点放下棋子是唯一选择,因为前面分析过放在匹配点一定输
接下来YY一定会走一条非匹配边到匹配点,因为如果还有非匹配点的话当前点一定不是非匹配点
到了匹配点AA就可以走匹配边了,而且一直走到他赢为止,为什么呢?假设当前匹配点可以到达一个非匹配点,那么一定可以再次增广,这就不满足匹配算法结束条件,不存在的。
所以说我们要求出所有可能是非匹配点的点
这就有点技巧了,考虑我们的匹配点,如果他可以到非匹配点,那么它将当前匹配边转向指向那个非匹配点是对答案没有影响的,而当前匹配点就变成了非匹配点,所以它就成为了一个答案。
由此得出了算法

枚举所有的非匹配点,从这个点开始,找一条到达匹配点的非匹配边,这个匹配点有一个匹配v,现在假设我们将当前点与匹配点匹配,那么v点成了非匹配点,于是乎就再dfs v点重复同样的步骤,即可找出所有的非必定匹配点

#include <bits/stdc++.h>#define mp make_pairusing namespace std; typedef pair< int, int > pp;int n, m, top, ord[105][105], head[10005], tot;vector< int > pe;pp arc[10005]; struct Node{    int y, nxt;    Node() {    }    Node( int y, int nxt ) : y(y), nxt(nxt) {   }} e[100005]; void Adde( int x, int y ){    e[++top] = Node(y, head[x]), head[x] = top;    e[++top] = Node(x, head[y]), head[y] = top;} char s[105][105]; bool vis[10005], ans[10005];int mat[10005]; bool Find( int u ){    for(int i = head[u]; i; i = e[i].nxt)    {        int v = e[i].y;        if(vis[v]) continue;        vis[v] = 1;        if(!mat[v] || Find(mat[v])) return (mat[u] = v, mat[v] = u);    }    return false;} void Hung(){    for(int i = 0; i < (int)pe.size(); ++i)    {        if(mat[pe[i]]) continue;        memset(vis, 0, sizeof(vis));        tot += Find(pe[i]);    }} void Dfs( int u ){    ans[u] = 1;    for(int i = head[u]; i; i = e[i].nxt)    {        int v = e[i].y;        if(mat[v] && !ans[mat[v]]) Dfs(mat[v]);    }} int main(){    cin >> n >> m;    for(int i = 1; i <= n ; ++i)        scanf( "%s", s[i] + 1 );    for(int i = 1; i <= n; ++i)        for(int j = 1; j <= m; ++j)        {            ord[i][j] = (i - 1) * m + j;            arc[ord[i][j]] = mp(i, j);            if(s[i][j] == '.')            {                if(s[i + 1][j] == '.') Adde(ord[i][j], ord[i][j] + m);                if(s[i][j + 1] == '.') Adde(ord[i][j], ord[i][j] + 1);                if(s[i - 1][j] == '.') Adde(ord[i][j], ord[i][j] - m);                if(s[i][j - 1] == '.') Adde(ord[i][j], ord[i][j] - 1);                pe.push_back(ord[i][j]);            }        }    Hung();    if(tot * 2 == pe.size())    {        puts("LOSE");        return 0;    }    puts("WIN");    for(int i = 0; i < (int)pe.size(); ++i)        if(!mat[pe[i]]) Dfs(pe[i]);    for(int i = 0; i < (int)pe.size(); ++i)        if(ans[pe[i]]) printf( "%d %d\n", arc[pe[i]].first, arc[pe[i]].second );    return 0;}