POJ 2688 简单的TSP问题,状压DP

来源:互联网 发布:openwrt端口转发 编辑:程序博客网 时间:2024/04/30 09:07

题意:

考虑一个被分为 W × H 网格的房间,机器人是矩形的,大小为 1 × 1。房间内的格子被分为干净的,脏的和障碍物三种。机器人不能踏上障碍物,而机器人只要经过一个脏的格子,它就会被清洁成干净的格子。
机器人每步可以向四个方向(上、下、左、右)之一走一步,进入在这个方向上和它相邻的格子。机器人可以经过一个格子多次。
你的任务是求得机器人清理干净整个房间(即把所有的脏格子清洁成干净格子)至少需要走多少步。

输入文件包含多个测试点。
每个测试点的第一行包含两个空格分隔的整数 W 和 H。之后 H 行,每行包含一个长度是 W 字符的字符串,字符串中的每个字符表示房间的一个格子,且为以下字符之一:
.:干净格子;
*:脏格子;
x:障碍物;
o:机器人所在位置;
机器人所在位置是一个干净格子。
输入文件以 0 0 结尾。

对于每个测试点,在单独的一行内输出答案。
如果无解,输出 -1。

TSP问题好难的样子,好像要用什么蚁群算法?
不过这种数据范围小的可以直接用状压DP水过。
标准做法就是f[i][S]表示当前在i,未经过的点的集合是S时还需要最少的步数。

对于这道题,因为脏点不超过10个,所以可以用状压DP,复杂度O(2^10*10)(因为起点确定,所以是10不是10^2)。

先预处理出TSP问题中的n^2条边,就是每两个脏点之间的最短路。之后直接DP即可。

#include <cstdio>#include <queue>#include <algorithm>#include <cstring>using namespace std; int n, m, num, d[405][405], pos[15], f[15][1<<11];char map[405];bool vis[405];queue <int> q;int id(int x, int y){    return (x-1)*m + y;}void BFS(int i){    vis[i] = 1;    d[i][i] = 0;    q.push(i);    while(!q.empty()){        int u = q.front(); q.pop();        while(map[u] == 'x' && !q.empty())         {u = q.front(); q.pop();}        if(map[u] == 'x') break;        if(u+1 <= id(n, m) && !vis[u+1] && u % m){            d[i][u+1] = d[i][u] + 1;            vis[u+1] = 1; q.push(u+1);        }        if(u-1 > 0 && !vis[u-1] && u % m != 1){            d[i][u-1] = d[i][u] + 1;            vis[u-1] = 1; q.push(u-1);        }        if(u+m <= id(n, m) && !vis[u+m]){            d[i][u+m] = d[i][u] + 1;            vis[u+m] = 1; q.push(u+m);        }        if(u-m > 0 && !vis[u-m]){            d[i][u-m] = d[i][u] + 1;            vis[u-m] = 1; q.push(u-m);        }    }}int dp(int i, int j){    if(f[i][j] >= 0) return f[i][j];    f[i][j] = 1 << 30;    for(int k = 0; k < num; k++) if((j>>k)&1){        f[i][j] = min(f[i][j], dp(k+1, j-(1<<k)) + d[pos[i]][pos[k+1]]);        }    return f[i][j];}int main(){    while(scanf("%d %d", &m, &n) && n){        memset(  d,-1, sizeof   d);        memset(  f,-1, sizeof   f);        memset(pos, 0, sizeof pos);        memset(map, 0, sizeof map);        num = 0;        for(int i = 1; i <= n; i++){            scanf("%s", map+id(i, 1));        }           for(int i = id(n, m); i; i--){            if(map[i] == 'o') pos[0] = i;            if(map[i] == '*') pos[++num] = i;        }           bool flag = 0;        for(int i = 0; i <= num; i++){            memset(vis, 0, sizeof vis); BFS(pos[i]);            for(int j = 0; j <= num; j++){                if(d[pos[i]][pos[j]] < 0){                    flag = 1; break;                }               }        }   if(flag) {puts("-1"); continue;}        int beg = 0;        for(int i = 0; i <= num; i++){            if(i != num) beg += (1 << i);            f[i][0] = 0;            for(int j = 0; j < num; j++){                if(i == j+1) continue;                f[i][1<<j] = d[pos[i]][pos[j+1]];                   }        }           printf("%d\n", dp(0, beg));     }    return 0;}
0 0
原创粉丝点击