hdu4771_2013亞洲區域賽杭州站(狀態壓縮bfs)


///////////////////////////////////////////////////////////////////////////////////////////////////////
作者: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[N][N][N];
char input[N][N];
int maze[N][N];
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 );
}
發佈了50 篇原創文章 · 獲贊 9 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章