一道用到二进制位加记忆化搜索的dp题

We are planning an orienteering game.

The aim of this game is to arrive at thegoal (G) from the start (S) with the shortest distance.

However, the players have to pass all thecheckpoints (@) on the map.

An orienteering map is to be given in thefollowing format.

########

#@....G#

##.##@##

#..@..S#

#@.....#

########

In this problem, an orienteering map is tobe given.

Calculate the minimum distance from thestart to the goal with passing all the checkpoints.

Specification

* A map consists of 5 characters asfollowing.

You can assume that the map does notcontain any invalid characters and

the map has exactly one start symbol 'S'and exactly one goal symbol 'G'.

* 'S' means the orienteering start.

* 'G' means the orienteering goal.

* '@' means an orienteering checkpoint.

* '.' means an opened-block that playerscan pass.

* '#' means a closed-block that playerscannot pass.

* It is allowed to move only by one stepvertically or horizontally (up, down, left, or right) to the

next block.

Other types of movements, such as movingdiagonally (left up, right up, left down and right down)

and skipping one or more blocks, are NOTpermitted.

* You MUST NOT get out of the map.

* Distance is to be defined as the numberof movements to the different blocks.

* You CAN pass opened-blocks, checkpoints,the start, and the goal more than once if necessary.

* You can assume that parameters satisfyfollowing conditions.

* 1 <= width <= 100

* 1 <= height <= 100

* The maximum number of checkpoints is 18.

* Return -1 if given arguments do notsatisfy specifications, or players cannot arrive at the goal

from the start by passing all thecheckpoints.

 

Input

The input is to be given in the followingformat, from the standard input.

W H

Row1

Row2

...

RowH

The first row is to describe the width andthe height of the orienteering map, sectioned by a space.

From the second row, map information is tobe given for exactly the same number of rows as the

height.

Each row contains exactly the same numberof letters as the width.

See “Specification” for details of thesymbols contained in the map.

Output

Output into the standard output, and put areturn.

**DO NOT forget to delete debug outputsbefore submission** .

Implementation

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
#define inf (1<<29)
const int maxn = 18;
int value[maxn][(1<<maxn)];
bool state[maxn][(1<<maxn)];
int n , m , cnt;
char ch[111][111];
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
struct Node {
    int id , x , y;
}p[110];
struct node {
    int x , y;
    node () {}
    node (int x,int y) : x(x) , y(y) {};
};
int Id[110][110];
int mp[110][110];
bool vis[110][110];
int gg[33][33];

int ss , tt;

bool inmap(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m;
}

queue <node> q;

void bfs(int id) {
    while(!q.empty()) q.pop();
    int x = p[id].x , y = p[id].y;
    memset(mp, -1, sizeof(mp));
    memset(vis, false, sizeof(vis));
    mp[x][y] = 0;
    node u = node(x , y);
    q.push(u);
    while(!q.empty()) {
        u = q.front(); q.pop();
        vis[u.x][u.y] = false;
        for(int i=0;i<4;i++) {
            int x = u.x + dir[i][0];
            int y = u.y + dir[i][1];
            if(!inmap(x, y)) continue;
            if(mp[x][y] == -1 || mp[x][y] > mp[u.x][u.y]+1) {
                mp[x][y] = mp[u.x][u.y] + 1;
                if(!vis[x][y]) {
                    vis[x][y] = true;
                    node v = node(x, y);
                    q.push(v);
                }
            }
        }
    }
}

void debug() {
    puts("debug");
    for(int i=0;i<cnt;i++) {
        for(int j=0;j<cnt;j++) {
            printf("%d ", gg[i][j]);
        }
        puts("");
    }
}

bool init() {
    for(int i=0;i<n;i++) scanf("%s" , ch[i]);
    cnt = 0;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if(ch[i][j] == '@') {
                Id[i][j] = cnt;
                p[cnt].x = i;
                p[cnt].y = j;
                p[cnt].id = cnt ++;
            }
    ss = cnt ; tt = cnt + 1;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++) {
            if(ch[i][j] == 'S') {
                Id[i][j] = ss;
                p[ss].x = i;
                p[ss].y = j;
                p[ss].id = ss;
            }
            else if(ch[i][j]  == 'G') {
                Id[i][j] = tt;
                p[tt].x = i;
                p[tt].y = j;
                p[tt].id = tt;
            }
        }
    cnt += 2;
    for(int i=0;i<cnt-1;i++) {
        bfs(i);
        for(int j=0;j<cnt;j++) {
            int x = p[j].x;
            int y = p[j].y;
            int diss = mp[x][y];
            gg[i][j] = gg[j][i] = diss;
            if(diss == -1) return false;
        }
    }
    //debug();
    return true;
}

int dfs(int pos, int sta) {
    if(state[pos][sta]) return value[pos][sta];
    state[pos][sta] = true;
    int cc = 0;
    for(int i=0;i<cnt-2;i++) if((1<<i) & sta) cc ++;
    //cout << "cc is " << cc << endl;
    if(cc == 1) return (value[pos][sta] = gg[ss][pos]);
    value[pos][sta] = inf;
    int sta_before = sta ^ (1<<pos);
    for(int i=0;i<cnt-2;i++) {
        int tmp = inf;
        //if(gg[i][pos] < 0) cout << "hello world!!!!!!!!!!!!!!!!!" << endl;
        if(sta_before & (1<<i)) tmp = dfs(i, sta_before) + gg[i][pos];
        if(tmp < value[pos][sta]) value[pos][sta] = tmp;
    }
    return value[pos][sta];
}

void debug2() {
    puts("debug2");
    for(int i=0;i<cnt-2;i++)
        cout << "haha : " << dfs(i, 1<<(i)) << endl;
    puts("end of debug2");
    for(int i=0;i<4;i++) {
        for(int j=14;j<16;j++) {
        //int j = 14;
            if((1<<i) & j) printf("%d : %d : %d\n" , i , j , dfs(i, j));
        }
    }
}

int main() {
    while(scanf("%d%d" , &n, &m) != EOF) {
        if(!init()) { puts("-1"); continue; }
        if(cnt - 2 == 0) {
            int ans = gg[ss][tt];
            printf("%d\n" , ans);
        }
        //cout << "cnt is " << cnt <<endl;
        //cout << "check : " << (1<<(cnt-2))-1 << endl;
        memset(state, false, sizeof(state));
        int ans = inf;
        for(int i=0;i<cnt-2;i++) {
            int tmp = dfs(i, (1<<(cnt-2))-1) + gg[i][tt];
            //cout << "tmp : " << tmp << endl;
            if(tmp < ans) ans = tmp;
        }
        //for(int i=0;i<cnt-2;i++)
        printf("%d\n" , ans);
        //debug2();
    }
    return 0;
}


/*
########
#@....G#
##.##@##
#..@..S#
#@.....#
########

*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值