hdu 4101 Ali and Baba【BFS好题】

Ali and Baba

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 2172    Accepted Submission(s): 460

Problem Description

There is a rectangle area (with N rows and M columns) in front of Ali and Baba, each grid might be one of the following:

1. Empty area, represented by an integer 0.

2. A Stone, represented by an integer x (x > 0) which denote the HP of this stone.

3. Treasure, represented by an integer -1.

Now, Ali and Baba get the map of this mysterious area, and play the following game:

Ali and Baba play alternately, with Ali starting. In each turn, the player will choose a stone that he can touch and hit it. After this operation, the HP of the stone that been hit will decrease by 1. If some stone’s HP is decreased to 0, it will become an
empty area. Here, a player can touch a stone means

there is path consist of empty area from the outside to the stone. Note that two grids are adjacent if and only if they share an edge.

The player who hits the treasure first wins the game.

Input

The input consists several testcases.

The first line contains two integer N and M (0 < N,M <= 300), the size of the maze.

The following N lines each contains M integers (less than 100), describes the maze, where a positive integer represents the HP of a stone, 0 reperents an empty area, and -1 reperents the treasure.

There is only one grid contains the treasure in the maze.

Output

“Ali Win” or “Baba Win” indicates the winner of the game.

Sample Input

3 3

1 1 1

1 -1 1

1 1 1

Sample Output

Baba Win

Source

2011 Alibaba-Cup Campus Contest

题目大意:给你一个n*m的图,图内有三种值分别代表:

1、0 代表空地

2、-1代表宝藏

3、1-100表示石头的血量值。

对于游戏的规则如下:谁先拿到宝藏谁赢,Ali先手,对于Ali和Baba来说,只能向上下左右四个方向走,每人每个回合必须攻击一个石头并让其减少一个血量,也就是说,如果有一条路从边缘任意(x==1||x==n||y==1||y==m)一点出发,如果能够走到-1,那么就相当于赢了。

思路:

(这个题真的是需要多方向多方面多角度来考虑的一个题,真的是很好很好很好很好的一个题。)

1、首先,如果有一条路能够从边缘一点出发,直接有一条路径能够保证不遇到石头的情况下直接走到宝藏上,因为Ali先手,所以Ali这种情况下就赢了,不需要继续判断了。这个问题我们可以直接从宝藏开始广搜,如果走到了边缘,就属于满足情况,这部分还是比较好实现的。

2、

如果不满足刚才所诉的情况辣么我们需要继续思考。

我们的目的其实很简单,目标也很明确,那就是来寻找一些石头,使得干掉这些个石头之后剩下的石头里边干掉任何一个都会使得一方胜利的情况。详细点说,对于样例来讲,这些需要找到的点(石头)是(1,1)(1,3)(3,1)(3,3),然后对这些点进行奇偶判定即可。如果是偶数,那么Baba会赢,否则Ali会赢。

然后我们就朝向这个目标来继续思考。

我们需要找到这些个目标点,首先要明确一个界限,这个界限就是将宝藏围住的一个距离宝藏最近的那个石头圈。

例如这个样例:

7 7
1 1 1 1 1 1 1
1 1 0 0 0 0 1
1 0 1 1 1 0 1
1 0 1 -1 1 0 1
1 0 1 1 1 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1

明显图里边有两个石头圈,我们要找的石头圈是最里边这一圈,辣么最外边那一圈那些店都是目标点。

辣么也不难理解:这些目标点是在这个界限之外的点,所以如果界限之内有石头,这些石头其实就是无关石头

如这种样例:

7 7
1 1 1 1 1 1 1
1 1 0 0 0 0 1
1 0 0 1 1 0 1
1 0 1 1 3 0 1
1 0 0 1 0 0 1
1 0 0 -1 0 0 1
1 1 1 1 1 1 1

明显宝藏上边的六个点就是刚刚所说的无关点。

这样我们就能确定出三种石头点和一个界限。

三种石头点:

一种是界限上的石头点(有一部分界限上的石头也属于目标点),一种是界限外的石头点,也就是我们所说的目标点,另外一种石头点,就是界限内的无关点。

确定了大体内容,我们也就明确了做题的大方向:找到界限,抛掉无关点,加和目标点。

目标点=界限外的石头点血量值加和+界限上石头点大于1的部分、

说到这里可能大家的思路也是比较清晰的了,这里再综合性的写一下:

先看看先手的Ali能否直接找到宝藏,如果可以,直接退出,如果不可以,继续判断,继续判断的目标:找到目标石头点,使得最后剩下的石头圈将宝藏整好围起来,而且这个时候界限圈上的点的石头血量值都为1.所以目标点=界限外的石头点血量值加和+界限上石头点大于1的部分

然后我们分块来写代码:

1、确定界限圈,并判断是否先手的Ali能否直接找到宝藏:

void Bfs(int x,int y)
{
    memset(vis,0,sizeof(vis));
    now.x=x;
    now.y=y;
    vis[x][y]=1;
    queue<zuobiao >s;
    s.push(now);
    while(!s.empty())
    {
        now=s.front();
        if(now.x==1||now.x==n||now.y==1||now.y==m)//如果先手Ali能够直接找到宝藏
        {
            ok=1;//标记上
            return ;
        }
        s.pop();
        for(int i=0;i<4;i++)
        {
            nex.x=now.x+fx[i];
            nex.y=now.y+fy[i];
            if(nex.x>=1&&nex.x<=n&&nex.y>=1&&nex.y<=m&&vis[nex.x][nex.y]==0)//如果在走的范围内,并且不重复走
            {
                vis[nex.x][nex.y]=1;//标记上这些点都走过了,就是说这些点属于界限圈内,包括界限圈
                if(a[nex.x][nex.y]==0)//如果走到的点是0,就可以继续走。
                {
                    s.push(nex);
                }
            }
        }
    }
    return ;
}

这样,vis【x】【y】=1的点,就是在界限圈内的点,同时也确定了界限圈、

2、对目标点进行统计值加和:

这里注意一个点:对界限上的点千万不要多次加和。界限外的点一定要标记完全。

void Bfs2(int x,int y)//<span style="font-family: Arial, Helvetica, sans-serif;">在图外边加一圈值为0的隐式图</span>
{
    memset(vis2,0,sizeof(vis2));
    now.x=x;
    now.y=y;
    queue<zuobiao >s;
    s.push(now);
    vis2[x][y]=1;
    while(!s.empty())
    {
        now=s.front();
        s.pop();
        for(int i=0;i<4;i++)
        {
            nex.x=now.x+fx[i];
            nex.y=now.y+fy[i];
            if(nex.x>=0&&nex.x<=n+1&&nex.y>=0&&nex.y<=m+1&&vis2[nex.x][nex.y]==0&&vis2[nex.x][nex.y]!=2)//能在走的范围内走,并且不重复走一个点,另外要注意的一个点是不要对界限圈上的点重复走
            {
                if(vis[nex.x][nex.y]==0)//界限圈外的点
                {
                    vis2[nex.x][nex.y]=1;
                    s.push(nex);
                }
                if(vis[nex.x][nex.y]==1)//界限圈上的点
                {
                    vis2[nex.x][nex.y]=2;
                    sum+=a[nex.x][nex.y]-1;//这块特殊处理一下,使得界限圈上的石头点血量值变成1,
                }
            }
        }
    }
    for(int i=0;i<=n+1;i++)
    {
        for(int j=0;j<=m+1;j++)
        {
            if(vis2[i][j]==1)sum+=a[i][j];//界限外的点进行加和
        }
    }
}

最后是完整的AC代码:

#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
struct zuobiao
{
    int x,y;
}now,nex;
int a[505][505];
int vis[505][505];
int vis2[505][505];
int fx[4]={0,0,1,-1};
int fy[4]={1,-1,0,0};
int n,m,ok,sum;
void Bfs(int x,int y)
{
    memset(vis,0,sizeof(vis));
    now.x=x;
    now.y=y;
    vis[x][y]=1;
    queue<zuobiao >s;
    s.push(now);
    while(!s.empty())
    {
        now=s.front();
        if(now.x==1||now.x==n||now.y==1||now.y==m)
        {
            ok=1;
            return ;
        }
        s.pop();
        for(int i=0;i<4;i++)
        {
            nex.x=now.x+fx[i];
            nex.y=now.y+fy[i];
            if(nex.x>=1&&nex.x<=n&&nex.y>=1&&nex.y<=m&&vis[nex.x][nex.y]==0)
            {
                vis[nex.x][nex.y]=1;
                if(a[nex.x][nex.y]==0)
                {
                    s.push(nex);
                }
            }
        }
    }
    return ;
}
void Bfs2(int x,int y)
{
    memset(vis2,0,sizeof(vis2));
    now.x=x;
    now.y=y;
    queue<zuobiao >s;
    s.push(now);
    vis2[x][y]=1;
    while(!s.empty())
    {
        now=s.front();
        s.pop();
        for(int i=0;i<4;i++)
        {
            nex.x=now.x+fx[i];
            nex.y=now.y+fy[i];
            if(nex.x>=0&&nex.x<=n+1&&nex.y>=0&&nex.y<=m+1&&vis2[nex.x][nex.y]==0&&vis2[nex.x][nex.y]!=2)
            {
                if(vis[nex.x][nex.y]==0)
                {
                    vis2[nex.x][nex.y]=1;
                    s.push(nex);
                }
                if(vis[nex.x][nex.y]==1)
                {
                    vis2[nex.x][nex.y]=2;
                    sum+=a[nex.x][nex.y]-1;
                }
            }
        }
    }
    for(int i=0;i<=n+1;i++)
    {
        for(int j=0;j<=m+1;j++)
        {
            if(vis2[i][j]==1)sum+=a[i][j];
        }
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        int sx,sy;
        memset(a,0,sizeof(a));
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&a[i][j]);
                if(a[i][j]==-1)
                {
                    sx=i;
                    sy=j;
                }
            }
        }
        ok=0;
        sum=0;
        Bfs(sx,sy);
        if(ok==1)
        {
            printf("Ali Win\n");
            continue;
        }
        Bfs2(0,0);
        if(sum%2==0)
        {
            printf("Baba Win\n");
        }
        else printf("Ali Win\n");
    }
}
时间: 2024-10-10 07:45:29

hdu 4101 Ali and Baba【BFS好题】的相关文章

HDU 4101 Ali and Baba

两次广搜 #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<algorithm> using namespace std; const int maxn=305; int N,M,Sx,Sy; int Map[maxn][maxn]; int Y[maxn][maxn]; int e[maxn][maxn]; int flag[maxn][max

!HDU 4101 Ali and Baba-博弈-(bfs&amp;dfs扫描二维点)

题意:目标是拿到值为-1的宝石,但是前提是要有一条从二维格子外面到宝石的通路,如果没有就要每次选一个石头使它的值减1,直到石头的值为0则变为通路,能选这个石头的前提也是有一条格子外到该石头的通路,A和B开始游戏,两人轮流来,每次选一个石头,A先开始,求由输入的条件,谁能赢. 分析: 博弈问题,两人会把围住宝石的一圈石头外面的石头全部敲碎然后才选这一圈石头,所以就是计算这一圈石头外面的所有石头的值的和,再加上这一圈石头的值减一的和,通过奇偶就能判断谁赢. 实现方法:从宝石dfs找出围住它的一圈石头

hdu 1180 诡异的楼梯 BFS 这题相当坑爹啊,需要注意几点

诡异的楼梯 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) Total Submission(s): 9813    Accepted Submission(s): 2428 Problem Description Hogwarts正式开学以后,Harry发现在Hogwarts里,某些楼梯并不是静止不动的,相反,他们每隔一分钟就变动一次方向. 比如下面的例子里,一开始楼梯在竖

HDU 1253 胜利大逃亡 BFS 简单题

题意: Ignatius要从迷宫的(1,1,1)在时间t内跑到(a,b,c),问可不可能. (题目本来是从(0,0,0)跑到(a-1,b-1,c-1)的) 简单的3维bfs 加剪枝: a+b+c-3>t  速度会快不少. 不过我这里没有加. Input 输入数据的第一行是一个正整数K,表明测试数据的数量.每组测试数据的第一行是四个正整数A,B,C和T(1<=A,B,C<=50,1<=T<=1000),它们分别代表城堡的大小和魔王回来的时间.然后是A块输入数据(先是第0块,然后

Saving Princess claire_(hdu 4308 bfs模板题)

http://acm.hdu.edu.cn/showproblem.php?pid=4308 Saving Princess claire_ Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2305    Accepted Submission(s): 822 Problem Description Princess claire_ wa

hdu 1312 Red and Black(BFS水题)

Red and Black Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 9684    Accepted Submission(s): 6021 Problem Description There is a rectangular room, covered with square tiles. Each tile is colore

(bfs+dfs) hdu 4101

Ali and Baba Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1799    Accepted Submission(s): 378 Problem Description There is a rectangle area (with N rows and M columns) in front of Ali and Bab

HDU4101 Ali and Baba (bfs+dfs+博弈)

题意: Ali 和Baba玩游戏,游戏是在给出的一个n*m的图中,有且仅有一个宝藏(-1)表示,图中其他位置可能是空地(0表示),也可能是石头(石头的HP用一个正数表示).二人轮流,每次游戏开始都是Ali先手,选手可以攻击石头,每次可以让石头HP减少一.问Ali是否可以胜利. 开始时,直接BFS 宝藏能扩展的最大的面积,因为面对都是1包围的-1 ,这个是必败态.但是WA了:然后想了很久,想到,可能存在宝藏所形成的连通的块是个环形,把其他的石头包围在里面,这样,这些石头就等于是没用的了.所以不得不

hdu 1885 Key Task (三维bfs)

题目 之前比赛的一个题, 当时是崔老师做的,今天我自己做了一下.... 还要注意用bfs的时候  有时候并不是最先到达的就是答案,比如HDU 3442 这道题是要求最小的消耗血量伤害,但是并不是最先到达目标点的路径 就是最小的伤害,因为每一个点的伤害是 不一样的, 这种情况要用优先队列优化, 对伤害优化. 题意:*开始, X出口, b, y, r, g 代表钥匙,分别可以开B, Y, R, G颜色的门, 钥匙可以多次使用.问最短的步骤. 思路:vis[][][]数组开三维,第三维记录状态 是否拿