您的位置:首页 > 其它

hdu4771_2013亚洲区域赛杭州站(状态压缩bfs)

2015-07-28 14:35 429 查看
///////////////////////////////////////////////////////////////////////////////////////////////////////

作者:tt2767

声明:本文遵循以下协议自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0

查看本文更新与讨论请点击:http://blog.csdn.net/tt2767

链接被删请百度: CSDN tt2767

///////////////////////////////////////////////////////////////////////////////////////////////////////

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4771

这题从中午做到晚上啊,收获还是比较多的。。。

学到的几点:

1.状态压缩:把状态压成二进制,通过查看二进制的每一位来判断状态。

2.带状态的bfs,虽然原来做过一道,但之前是还是不太明白

3.把地图数据化表示很有用

4.自己包装输入

5.。。。。。。。。。。

题解:

先把输入的数据处理一下,记录起点之后,数据化地图:

墙为-1,宝藏为1,2,4,8(二进制就是0001,0010,0100,1000),起点和路都为0.

每次通过加和记录已找到宝藏的状态

eg:找到了2,8记录为10(0010+1000=1010)

可用按位与来判断是否捡过宝藏

宝藏可能在任何地方,如果在墙里面,直接输出-1;

#include<string>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;

typedef  long long int LL;
const int INF = 0x3f3f3f3f ;
const long double PI = acos(0.0) * 2.0;
const int N = 200;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
const int change[] ={0,1,2,4,8};
struct P
{
    int x,y,step,num;
    P(int x,int y,int step,int num):x(x),y(y),step(step),num(num){}
    P(){}
};

P s;
bool vis

;
char input

;
int maze

;
int sum,n,m;
bool flag;//是否有宝物在墙里?
int bfs();
bool pass(P);//不管走没走过,这个位置是可以走的
bool read();

int main()
{
    while( read() )
        printf("%d\n",bfs());
    return 0;
}

int bfs()
{
    if(flag)    return -1;  //如果在墙里是不可能找全的

    memset(vis,0,sizeof(vis));
    queue<P> q;
    vis[s.x][s.y][s.num] = 1;
    q.push(s);
    while(!q.empty())
    {
        P p = q.front();q.pop();
        if(p.num == sum )  return p.step;

        for(int i = 0 ; i < 4 ; i++)
        {
            P now = p; //先继承上一次的属性
            now.x += dx[i];
            now.y += dy[i];

            if( pass(now) )
            {
                if(maze[now.x][now.y] > 0 )  // 本题关键步骤!!
                {
                    int mark1 = maze[now.x][now.y]; //宝藏的标记
                    int mark2 = now.num;                   //人的标记

                    if( (mark1&mark2)  == 0 ) //按位与判断,如果没捡过此宝藏,就把它捡起来
                    {
                        now.num += maze[now.x][now.y];
                    }
                }

                if(!vis[now.x][now.y][now.num])
                {
                    now.step = p.step + 1;
                    vis[now.x][now.y][now.num] = 1;
                    q.push(now);
                }
            }
        }
    }

    return -1;
}

bool read()
{
    memset(input,'\0',sizeof(input));
    memset(maze,0,sizeof(maze));

    if(scanf("%d%d",&n,&m) != 2 || !(n+m))  return false;

    for(int i = 1 ; i <= n ; i++)
    {
        getchar();
        for(int j = 1 ; j <= m ; j++)
        {
            scanf("%c",&input[i][j]);
            if(input[i][j] == '.')  //地图数据化
            {
                maze[i][j] = 0;
            }
            else if(input[i][j] == '@')
            {
                maze[i][j]  = 0;
                s = P(i,j,0,0);
            }
            else
            {
                maze[i][j] = -1;
            }
        }
    }

    sum = 0;
    flag = false;
    int k;
    scanf("%d",&k);
    for(int i = 1 ; i <= k ; i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if(maze[x][y] < 0)    flag = true; //在墙里的话标记一下
        maze[x][y] += change[i];
        sum+= maze[x][y];
    }

    return true;
}

bool pass(P z)
{
    return (0 < z.x && z.x<= n && 0 < z.y && z.y <= m && maze[z.x][z.y] != -1 );
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: