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#
#@.....#
########
*/