思路:假设黄金数量一共有k个,给这些黄金编号为0 ~ k-1并且把他们的位置都存起来。起点编号为k
那么定义dp[s][i] : 当前已经采集的黄金集合为s, 并且现在处于编号为k的位置
对于将要采集的黄金编号 j ,有如下转移方程
d[s | (1 << j)][j] = min(dp[s | (1 << j )][j], dp[s][i] + dist(i, j))
初始点为dp[0][k] = 0;
终点也为dp[0][k],是经典的TSP问题.
还有一个wa点就是在任意点,可以走8个方向。所以点(x1, y1) 到(x2, y2)的最短距离就
应该为max(abs(y2-y1), abs(x2-x1));
/***********************************************
* Author: fisty
* Created Time: 2015-08-24 21:32:39
* File Name : 1057.cpp
*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define Memset(x, a) memset(x, a, sizeof(x))
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
#define FOR(i, a, b) for(int i = a;i < b; i++)
#define lson l, m, k<<1
#define rson m+1, r, k<<1|1
#define MAX_N 21
int dp[1<<(MAX_N-4)][MAX_N*2];//dp[s][i] 当前采集黄金集合为s并且在位置i
char G[MAX_N][MAX_N];
int Q; //黄金数量
struct Point{
int x, y;
}p[MAX_N];
int t;
int m, n;
int dist(int i, int j){
Point a = p[i];
Point b = p[j];
int _x = abs(a.x - b.x);
int _y = abs(a.y - b.y);
int _max = max(_x, _y);
return _max;
}
void solve(){
Memset(dp, 0x3f);
dp[0][Q-1] = 0;
for(int s = 0;s < (1<<Q)-1; s++){
for(int i = 0;i < Q; i++){
for(int j = 0;j < Q; j++){
if(!((1<<j) & s)){
dp[s|(1<<j)][j] = min(dp[s|(1<<j)][j], dp[s][i] + dist(i, j));
// Debug(dist(i, j));
}
}
}
}
printf("%d\n", dp[(1<<Q)-1][Q-1]);
}
int main() {
//freopen("in.cpp", "r", stdin);
//cin.tie(0);
//ios::sync_with_stdio(false);
scanf("%d", &t);
int cnt = 1;
while(t--){
Q = 0;
Memset(p, 0);
int sx, sy;
scanf("%d%d", &m, &n);
for(int i = 0;i < m; i++){
scanf("%s", G[i]);
for(int j = 0;j < n; j++){
if(G[i][j]=='g'){
p[Q].x = i;
p[Q++].y = j;
}
if(G[i][j] == 'x'){
sx = i;
sy = j;
}
}
}
p[Q].x = sx;
p[Q++].y = sy;
printf("Case %d: ", cnt++);
solve();
}
return 0;
}