POJ 2688 Cleaning Robot(BFS + A* + 状态压缩DP)

题意:

给你一个N * M(1 ≤ N, M ≤ 20)的地图,'.'表示空位,'*'表示垃圾,'o'表示机器人的初始位置,'x'表示墙。请你计算机器人清理完所有的垃圾至少要走多少步。

机器人一旦走到垃圾上,垃圾就被清掉了。输入数据保证垃圾不多于10个。

思路:

1. 先 BFS 求出任意两个污点间所需要的最小步数。题目保证了污点数不超过 10 个,这时候可以应用经典的 TSP 模型,用状态压缩 dp 解决之;

2. dp[u][s] 代表以 u 结束的状态 s 需要经过的最小步数。 s 中的位代表已经选择了的污点,初始状态 dp[0][0] = 0, 其他赋值 INFS,求解 dp[i][ends] 最小值。

 

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

const int INFS = 0x3fffffff;
const int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
char grid[25][25];
int col, row, dis[15][15];
bool vis[25][25];

struct Dirty {
    int x, y;
} dirty[20] ;

struct ST {
    int x, y, step, f;
    ST(int _x, int _y, int _step, int _f) : x(_x), y(_y), step(_step), f(_f) {}
    bool operator < (const ST& other) const {
        return f > other.f;
    }
};

bool judge(int x, int y) {
    if (0 < x && x <= row && 0 < y && y <= col && grid[x][y] != 'x') {
        return true;
    }
    return false;
}

int getdiff(const Dirty& a, const Dirty& b) {
    return abs(a.x - b.x) + abs(a.y - b.y);
}

int bfs(const Dirty& src, const Dirty& dst) {
    priority_queue<ST> Q;
    Q.push(ST(src.x, src.y, 0, getdiff(src, dst)));
    memset(vis, false, sizeof(vis));
    vis[src.x][src.y] = true;

    while (!Q.empty()) {
        ST u = Q.top();
        Q.pop();

        if (u.x == dst.x && u.y == dst.y)
            return u.step;

        for (int i = 0; i < 4; i++) {
            Dirty v;
            v.x = u.x + dir[i][0];
            v.y = u.y + dir[i][1];
            if (judge(v.x, v.y) && !vis[v.x][v.y]) {
                vis[v.x][v.y] = true;
                int f = u.step + 1 + getdiff(v, dst);
                Q.push(ST(v.x, v.y, u.step + 1, f));
            }
        }
    }
    return -1;
}

int dp[12][1<<12];
int dirtycnt;

inline int getflag(int r) {
    return 1 << r;
}

int dfs(int state, int u) {
    if (dp[u][state] != INFS)
        return dp[u][state];

    int s = state ^ getflag(u - 1);
    if (s == 0) 
        return dis[0][u];

    for (int i = 1; i <= dirtycnt; i++) {
        if (s & getflag(i-1)) {
            dp[u][state] = min(dp[u][state], dfs(s, i) + dis[i][u]);
        }
    }
    return dp[u][state];
}

int main() {
    while (scanf("%d%d", &col, &row) && col && row) {
        memset(dirty, 0, sizeof(dirty));
        dirtycnt = 0;
        for (int i = 1; i <= row; i++) { 
            scanf("%s", &grid[i][1]);
            for (int j = 1; j <= col; j++) {
                if (grid[i][j] == '*') {
                    dirtycnt += 1;
                    dirty[dirtycnt].x = i;
                    dirty[dirtycnt].y = j;
                } else if (grid[i][j] == 'o') {
                    dirty[0].x = i; dirty[0].y = j;
                }
            }
        }

        bool flag = false;
        for (int i = 0; i <= dirtycnt; i++) {
            for (int j = i; j <= dirtycnt; j++) {
                if (i == j) {
                    dis[i][j] = 0;
                } else {
                    dis[j][i] = dis[i][j] = bfs(dirty[i], dirty[j]);
                    if (dis[i][j] == -1) {
                        flag = true; break; 
                    }
                }
            }
        }
        if (flag) {
            printf("-1\n"); continue;
        }

        int ends = getflag(dirtycnt) - 1;
        for (int i = 0; i <= dirtycnt; i++) {
            for (int j = 0; j <= ends; j++)
                dp[i][j] = INFS;
        }
        dp[0][0] = 0;
        int ans = INFS;
        for (int i = 1; i <= dirtycnt; i++)
            ans = min(ans, dfs(ends, i));
        printf("%d\n", ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kedebug/p/2979951.html