uva 1601 poj 3523 Morning after holloween [双广][DBFS]

写Astar写哭了。

这题难点在于状态的转移, 可以先枚举出5^3的状态然后判断合不合法,但是由于题目说了有很多墙壁,实际上没有那么多要转移的状态那么可以把底图抽出来,然后3个ghost在上面跑到时候就不必判断了,减少了两次无用的枚举。

一开始用邻接表建图,历遍时非常麻烦,后来改用用数组保存子节点(由于每个块的转移最多有5个,因此不用vector而用数组)。

减少代码的方法:1.结点没有3个时增加虚拟结点,2.把位置坐标二元组Hash成一个数,这点在建图时可以顺便完成(坐标范围0~15),3.把三个ghost的位置Hash成一个数字,方便push,但是注意重时不能直接用Hash掉的值,因为Hash以后数字范围很大。

这题为什么不适合Astar。因为Astar的估计用Manhattan距离需要知道坐标,因此不适合把二元组hash成数字,而且不能用一个数来压缩状态了,因为要加上估价值,代码很长,而且写出来以后不知道为什么一直挂在ghost有3个的情况,程序运行结果78。。。实际77。

poj不支持#include<bits/stdc++.h>

//Rey
#include<bits/stdc++.h>
using namespace std;
const int maxw = 16;
const int maxn = 150;//14*14*3/4+2 149

int s[3];
int t[3];
int w,h,n;
char maze[maxw][maxw+1];

int deg[maxn],G[maxn][5];

inline bool conflict(int a1,int b1,int a2,int b2){
    return a1 == a2 || (a1 == b2 && a2 == b1);
}
int vis1[maxn][maxn][maxn];
int vis2[maxn][maxn][maxn];
typedef vector<int> VINT;
VINT v1;
VINT v2;
VINT v3;
typedef VINT * PV;

inline int Hash(int a,int b,int c) {return a<<16|b<<8|c;}
int dBfs()
{
    v1.clear();v2.clear();v3.clear();
    memset(vis1,-1,sizeof(vis1));
    memset(vis2,-1,sizeof(vis2));
    PV q1 = &v1,q2 = &v2,nxt = &v3;
    int (*d1)[maxn][maxn] = vis1, (*d2)[maxn][maxn] = vis2;
    d1[s[0]][s[1]][s[2]] = 0;
    d2[t[0]][t[1]][t[2]] = 0;
    q1->push_back(Hash(s[0],s[1],s[2]));
    q2->push_back(Hash(t[0],t[1],t[2]));
    while(q1->size()&&q2->size()){
        if(q1->size()>q2->size()) swap(q1,q2),swap(d1,d2);
        for(int ii = 0,sz = q1->size(); ii < sz; ii++){
            int u = (*q1)[ii];
            int a = u>>16, b = (u>>8)&0xff, c = u&0xff;
            for(int i = 0; i < deg[a]; i++){
                int a1 = G[a][i];
                for(int j = 0; j < deg[b]; j++){
                    int b1 = G[b][j];
                    if(conflict(a1,a,b1,b)) continue;
                    for(int k = 0; k < deg[c]; k++){
                        int c1 = G[c][k];
                        if(conflict(c1,c,a1,a)||conflict(c1,c,b1,b)||~d1[a1][b1][c1]) continue;
                        d1[a1][b1][c1] = d1[a][b][c]+1;
                        if(~d2[a1][b1][c1]) { return d1[a1][b1][c1]+d2[a1][b1][c1]; }
                        nxt->push_back(Hash(a1,b1,c1));
                    }
                }
            }
        }
        q1->clear();
        swap(nxt,q1);
    }

    return -1;
}

void init()
{
    int cnt = 0;
    int id[maxw][maxw];
    const int dx[] = {-1, 1, 0, 0, 0};
    const int dy[] = { 0, 0,-1, 1, 0};
    int x[maxn];
    int y[maxn];

    for(int i = 0; i < h; i++)
    for(int j = 0; j < w; j++) {
        char ch = maze[i][j];
        if(ch != ‘#‘){
            x[cnt] = i; y[cnt] = j;  id[i][j] = cnt;
            if(‘A‘<= ch && ch <= ‘C‘) {t[ch-‘A‘] = cnt;}
            else if(‘a‘ <= ch && ch <= ‘c‘) {s[ch-‘a‘] = cnt; }
            cnt++;
            }
        }

    for(int i = 0; i < cnt; i++){
        deg[i] = 0;
         for(int k = 0; k < 5; k++) {
            int nx = x[i]+dx[k], ny = y[i]+dy[k];
            if(maze[nx][ny] != ‘#‘)
                G[i][deg[i]++] = id[nx][ny];
        }
    }
    if(n<=2) {deg[cnt] = 1; G[cnt][0] = cnt; s[2] = t[2] = cnt++; }
    if(n<=1) {deg[cnt] = 1; G[cnt][0] = cnt; s[1] = t[1] = cnt++; }
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%d",&w)&&w) {
        scanf("%d%d\n",&h,&n);
        for(int i = 0; i < h; i++)
            gets(maze[i]);//G[i-1]
            init();
            int ans = dBfs();
            printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-10-25 17:33:27

uva 1601 poj 3523 Morning after holloween [双广][DBFS]的相关文章

UVa 1601 || POJ 3523 The Morning after Halloween (BFS || 双向BFS &amp;&amp; 降维 &amp;&amp; 状压)

题意 :w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占用同一个位置,也不能在一步之内交换位置.输入保证所有空格连通,所有障碍格也连通,且任何一个2*2子网格中至少有一个障碍格.输出最少的步数.输入保证有解. 分析 :可以将当前所有小鬼的位置作为一个状态,然后模拟小鬼移动BFS拓展出其他可行状态并且顺带记录步数,直到所有的小鬼都到达终点.首先状态如何表示

[2016-02-24][UVA][1601][The Morning after Halloween]

时间:2016-02-24 15:49:41 星期三 题目编号:UVA 1601 题目大意:给定一个迷宫图,至多3个小写字母和等数目大写字符,求小写字母移动到大写字母的最少步数 迷宫宽度范围是4~16,字母个数是1~3, 分析:求最少步数,BFS,知道终点状态,可以用双向bfs优化 方法:BFS //单向bfs #include<iostream> #include<cstdio> #include<queue> #include<cstring> #inc

Uva 127 poj 1214 `Accordian&#39;&#39; Patience

 ``Accordian'' Patience  You are to simulate the playing of games of ``Accordian'' patience, the rules for which are as follows: Deal cards one by one in a row from left to right, not overlapping. Whenever the card matches its immediate neighbour on

POJ 3177 Redundant Paths (双连通)

题目地址:POJ 3177 找出各个双连通分量度数为1的点,然后作为叶子节点,那么ans=(叶子结点数+1)/2.需要注意的是有重边. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include

UVA 124 &amp; POJ 1270 Following Orders(拓扑排序)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=60 http://poj.org/problem?id=1270 Following Orders Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 3806   Accepted: 1507 Description Or

poj 3278 Catch That Cow(广搜)

Catch That Cow Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 45087   Accepted: 14116 Description Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,00

nyoj 999——师傅又被妖怪抓走了——————【双广搜】

师傅又被妖怪抓走了 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 话说唐僧复得了孙行者,师徒们一心同体,共诣西方.自宝象国救了公主,承君臣送出城西,沿路饥餐渴饮,悟空便为师傅去化斋,等悟空回来,悟净慌慌张张的对悟空说:“不好了,不好了”,还没等悟净说完,悟空说:“师傅又被妖怪抓走了”,悟净:“NO!” ,悟空一脸茫然,悟净:“师傅和二师兄都被妖怪抓走了”.悟空(晕!).为了防止悟空救人,妖怪先把唐憎和八戒分别藏起来,如果悟空在T分钟之后还没找到人,那必定是被妖怪吃

nyist 999 师傅又被妖怪抓走了 【双广搜 || BFS +状态压缩】

题目:nyist 999 师傅又被妖怪抓走了 分析:在一个图中只要看到D点和E点就行的最小步数,看到的定义是:也就是说两个人在同一行或者同一列,并且中间没有障碍物或者没有其他人就可以看到对方. 所以可以先预处理地图,把D点和E点所在的行列的' .'扩展为d和e,然后只要搜到d和e就可以,问题是只有d和e同时搜到才行,直接广搜肯定不行,我们可以在搜到d点之后然后在从当前点广搜e点,或者e点广搜d点,这样第一次搜到的点不一定是最优的,所以需要枚举所有情况才行,时间复杂度较高. 比较好的一种方法是BF

hdu.1043.Eight (打表 || 双广 + 奇偶逆序)

Eight Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 14380    Accepted Submission(s): 4044 Special Judge Problem Description The 15-puzzle has been around for over 100 years; even if you don'