UVa #1601 The Morning after Halloween (例题7-9)

86 篇文章 0 订阅

状态空间搜索。。不过状态数量比较多,很容易TLE


优化的方法:

1、压缩状态

因为地图最大16*16,所以可以用0-255来标记每一个格子,很轻松的将二维坐标变为一个整数

2、使用邻接表

如果每次都使用“尝试走一步看看行不行”的方法,会重复很多次无用的判断。所以用一个vector来保存每个空地相邻的空地,每次走路就遍历这个vector

3、判重的方法

一开始我用了State类型的map来判重,速度很慢。而使用整数来标记格子后,可以用一个三维数组(因为最多有三个ghost)进行判重,我自己测试时的速度就由20s提升到了1s


很搞笑的是我用普通bfs和双向bfs的速度差不多,而A*就会TLE(应该是我的启发函数设计的不好,我用的是三个ghost距离目的地的曼哈顿距离和)。



Run Time: 2.909s

#define UVa  "LT7-9.1601.cpp"

#include<cstring>
#include<cstdlib>
#include<cstdio>

#include<string>
#include<vector>
#include<queue>

using namespace std;


//Global Variables.
int w, h, n;
int m[20][20];
int dst[3][2], startPosition[3][2];
int step[2][5] = {{-1,0,1,0,0},{0,1,0,-1,0}};
vector<int> G[300];
int vis[300][300][300];
/

struct State {
    int dist;
    int g[3];
    int prev[3];
    State():dist(0){
        for(int i = 0; i < n; i ++) g[i] = startPosition[i][0] * w + startPosition[i][1];
    }
    void setprev (const State& prevS){
        for(int i = 0; i < n; i ++) prev[i] = prevS.g[i];
    }
    int is_arrived() {
        for(int i = 0; i < n; i ++) if(g[i] != dst[i][0] * w + dst[i][1]) return 0;
        return 1;
    }
    int collisionexchange() {
        if(dist == 0) return 0;             //starting state.
        for(int i = 0; i < n; i ++) for(int j = 0; j < n; j ++) if(i != j){
            if(g[i] == g[j]) return 1;              //collision
            if(g[i] == prev[j] && prev[i]== g[j]) return 1;        //exchange
        }
        return 0;       //##
    }
    bool operator < (const State& s) const {
        for(int i = 0; i < 3; i ++) { if(g[i] < s.g[i]) return true; if(g[i] > s.g[i]) return false; }
        return false;
    }
};


void solve() {
    State start = State();
    queue<State> q;
    q.push(start);

    while(!q.empty()) {
        State u = q.front(); q.pop();

        if(u.is_arrived()) { printf("%d\n", u.dist); return; }

        State newS;
        newS.setprev(u);
        newS.dist = u.dist + 1;

        int cur1 = u.g[0];
        for(int i = 0; i < G[cur1].size(); i ++) {
            int new1 = G[cur1][i];
            newS.g[0] = new1;
            if(n >= 2) {
                int cur2 = u.g[1];
                for(int j = 0; j < G[cur2].size(); j ++) {
                    int new2 = G[cur2][j];
                    newS.g[1] = new2;
                    if(n >= 3) {
                        int cur3 = u.g[2];
                        for(int k = 0; k < G[cur3].size(); k ++) {
                            int new3 = G[cur3][k];
                            newS.g[2] = new3;
                            if(!vis[newS.g[0]][newS.g[1]][newS.g[2]] && !newS.collisionexchange()) {
                                vis[newS.g[0]][newS.g[1]][newS.g[2]] = 1;
                                q.push(newS);
                            }
                        }
                    }
                    else if (n == 2) {
                        if(!vis[newS.g[0]][newS.g[1]][0] && !newS.collisionexchange()) {
                            vis[newS.g[0]][newS.g[1]][0] = 1;
                            q.push(newS);
                        }
                    }
                }
            }
            else if (n == 1) {
                if(!vis[newS.g[0]][0][0] && !newS.collisionexchange()) {
                    vis[newS.g[0]][0][0] = 1;
                    q.push(newS);
                }
            }
        }
    }
}
void read_floor() {
    char ch;
    int charPos[30]; memset(charPos, -1, sizeof(charPos));
    int cnt = 0;
    for(int i = 0; i < h; i ++) {
        for(int j = 0; j < w; j ++) {
            scanf("%c", &ch);
            if(j == 0) while(ch != '#') { scanf("%c", &ch); }
            if(ch == '#') m[i][j] = 0;

            else {
                m[i][j] = 1;
                if(isalpha(ch)) {
                    if(isupper(ch)) {
                        if(charPos[ch-'A'] == -1) {
                            dst[cnt][0] = i;
                            dst[cnt][1] = j;
                            charPos[ch-'A'] = cnt;
                            cnt ++;
                        }
                        else {
                            dst[charPos[ch-'A']][0] = i;
                            dst[charPos[ch-'A']][1] = j;
                        }
                    }
                    else {
                        if(charPos[ch-'a'] == -1) {
                            startPosition[cnt][0] = i;
                            startPosition[cnt][1] = j;
                            charPos[ch-'a'] = cnt;
                            cnt ++;
                        }
                        else {
                            startPosition[charPos[ch-'a']][0] = i;
                            startPosition[charPos[ch-'a']][1] = j;
                        }
                    }
                }
            }
        }
    }
}
void read_G() {
    for(int i = 0; i < h; i ++) {
        for(int j = 0; j < w; j ++) {
            int cur = i*w + j;
            if(m[i][j] == 0) continue;
            vector<int> vec;
            vec.push_back(cur);
            G[cur] = vec;

            for(int k = 0; k < 4; k ++) {
                int newR = i + step[0][k], newC = j + step[1][k];
                if(newR < 0 || newR > h || newC < 0 || newC > w || m[newR][newC] == 0) continue;
                int tmp = newR * w + newC;
                G[cur].push_back(tmp);
            }
        }
    }
}

int main() {
    while(scanf("%d%d%d", &w,&h,&n) && w && h && n) {
        memset(dst, -1, sizeof(dst));
        memset(startPosition, -1, sizeof(startPosition));
        memset(vis, 0, sizeof(vis));

        read_floor();
        read_G();
        solve();
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值