HDU 4101 Ali and Baba 博弈, 连通块

来源:互联网 发布:mac隐藏dock 怎么恢复 编辑:程序博客网 时间:2024/05/21 19:28

题目大意:

就是现在对于一个N*M的地图(N, M <= 300), 上面有的地方是空的用0表示, 有一个珠宝, 用-1表示珠宝的位置, 用正整数表示那个位置存在一个石头, 其HP就是那个整数

现在两个人博弈, 两人每次可以选择一个从外部碰到的石头敲一下, 被敲的石头HP - 1, 石头HP降为0的时候消失, 变成空地, 轮到谁不敲石头拿到珠宝谁就获胜

能碰到的石头的定义是从外部通过空地可以到达那个石头的旁边(上下左右), 珠宝也是这样, 与外界联通时便可以被拿到

两人轮流操作, Ali先Baba后, 问谁会获得珠宝取得胜利


大致思路:

首先如果珠宝一开始就能被拿到, Ali胜, 从-1开始dfs看能不能通过空地到达边界即可(当然最好是bfs, 不用爆栈)

否则的话一定是这个珠宝被石头包围了, 那么一这个珠宝为中心向周围bfs标记从这个-1能碰到的石头和空地为1

这里一定要注意并不是所有被标记为1的石头都是保护圈, 有一些没标记的也可能在保护圈内

例如这样的样例:

1  1 1 1 1 1 1 11

1  0 0 0 0 0 0 0 1

1 -1 0 0 0 1 1 1 1

1  0 0 0 0 0 0 0 1

1  0 1 1 1 1 0 0 1

1  0 1 1 1 10 0 1

1  0 1 1 1 1 0 0 1

1  0 0 0 0 0 0 0 1

1  1 1 1 1 1 1 11

里面有一整块1都是不敲的, 另外墙边突出的一块有一部分也是不敲的, 不敲的1标记为红色, 保护圈标记为绿色, 外围可以敲完的石头为蓝色, -1底色为黄色

那么红色的1懂事不用的, 绿色的都是敲到HP剩余为1的, 蓝色的都是外部石头可以周旋到敲完的

显然就是蓝色的HP和机上绿色的HP - 1的和的奇偶性决定胜负了

那么问题在于如何判断1是保护圈而不是圈内? 保护圈及其圈内都标记为1了

那么从外部开始bfs(我写的dfs...用bfs好些, 不爆栈) 把从外部在不碰绿色保护圈的条件下能碰到的都标记为2, 

那么能作为保护圈的石头和圈内的石头明显只有保护圈的石头旁边才有被标记为2的地方(在边界补上一圈空格一并标记为2即可这么判断了)

于是这个问题就没什么trick了...感觉还是比较好做的一个博弈吧


代码如下:

Result  :  Accepted     Memory  :  5704 KB     Time  :  296 ms

/* * Author: Gatevin * Created Time:  2015/7/20 15:23:05 * File Name: A.cpp */#pragma comment(linker, "/STACK:16777216")#include<iostream>#include<sstream>#include<fstream>#include<vector>#include<list>#include<deque>#include<queue>#include<stack>#include<map>#include<set>#include<bitset>#include<algorithm>#include<cstdio>#include<cstdlib>#include<cstring>#include<cctype>#include<cmath>#include<ctime>#include<iomanip>using namespace std;const double eps(1e-8);typedef long long lint;int sx, sy;int maz[500][500];int con[500][500];int n, m, N, M;int dx[] = {1, -1, 0, 0};int dy[] = {0, 0, 1, -1};int sum;//bool vis[500][500];void dfs(int nx, int ny)//标记所有可能是-1保护圈的位置为1{    con[nx][ny] = 1;//连通    if(maz[nx][ny] > 0) return;    for(int i = 0; i < 4; i++)    {        int tx = nx + dx[i];        int ty = ny + dy[i];        if(tx >= 1 && tx <= N && ty >= 1 && ty <= M && !con[tx][ty])            dfs(tx, ty);    }    return;}void dfs_out(int nx, int ny)//不碰-1所在的包围圈能碰到的石头全碎, 标记不碰包围圈能经过的位置为2{    if(nx < 0 || nx > N + 1 || ny < 0 || ny > M + 1) return;    if(con[nx][ny] == 1) return;    if(con[nx][ny] == 2) return;    if(maz[nx][ny] > 0) sum += maz[nx][ny];//-1分隔圈之外的石头可以敲到碎    con[nx][ny] = 2;    for(int i = 0; i < 4; i++)    {        int tx = nx + dx[i];        int ty = ny + dy[i];        dfs_out(tx, ty);    }    return;}bool check(int x, int y)//检查(x, y)处的-1的包围部分是否是其与外界的分隔石{    for(int k = 0; k < 4; k++)        if(con[x + dx[k]][y + dy[k]] == 2)//1, 2标记的交界, 一定是保护圈            return true;    return false;}int main(){    while(~scanf("%d %d", &n, &m))    {        N = n, M = m;        memset(maz, 0, sizeof(maz));        for(int i = 1; i <= n; i++)            for(int j = 1; j <= m; j++)            {                scanf("%d", &maz[i][j]);                if(maz[i][j] == -1)                    sx = i, sy = j;            }        memset(con, 0, sizeof(con));        //memset(vis, 0, sizeof(vis));        dfs(sx, sy);        sum = 0;        for(int i = 1; i <= n; i++)            for(int j = 1; j <= m; j++)            {                if(con[i][j] && (i == 1 || i == n || j == 1 || j == m) && maz[i][j] <= 0)//-1与外界是连通的                {                    puts("Ali Win");//先手必胜                    goto nex;                }            }        dfs_out(0, 0);        for(int i = 1; i <= n; i++)            for(int j = 1; j <= m; j++)            {                if(con[i][j] == 1 && check(i, j) && maz[i][j] > 0)//是-1连通块与外部的分隔石头, 敲到剩余HP == 1                    sum += maz[i][j] - 1;            }//注意-1的保护圈内部的石头是不敲的, 在博弈中敲它们没有意义        if(!(sum & 1)) puts("Baba Win");//和的奇偶便决定了胜负        else puts("Ali Win");        nex:;    }    return 0;}


0 0
原创粉丝点击