题目链接:FZU2186
【分析】因为宝物最多有10个,所以可以状压TSP来求,其实和HDU4568几乎一样,求出所有宝物之间的最短路,然后就是标准TSP问题啦。
【AC CODE】46ms
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <map>
//#include <unordered_map>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 100+10;
const int f[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
struct NODE{
int x,y;
NODE(int a = 0, int b = 0)
{
x = a;
y = b;
}
}p[15];
int h,w,mp[MAXN][MAXN], cnt, dis[15][15], d[MAXN][MAXN];
bool vis[MAXN][MAXN];
int bfs(int st, int ed)
{
queue<NODE> q;
clc(vis,0);
q.push(p[st]);
d[p[st].x][p[st].y] = 0;
vis[p[st].x][p[st].y] = 1;
while(!q.empty())
{
NODE now = q.front();q.pop();
if(now.x == p[ed].x && now.y == p[ed].y) return d[now.x][now.y];
rep(i,0,4)
{
int ni = now.x+f[i][0], nj = now.y+f[i][1];
if(0 <= ni && h > ni && 0 <= nj && w > nj && !vis[ni][nj] && mp[ni][nj] >= 0)
{
q.push(NODE(ni,nj));
d[ni][nj] = d[now.x][now.y]+1;
vis[ni][nj] = true;
}
}
}
return INF;
}
int dp[1<<13][15];
int main()
{
#ifdef SHY
freopen("e:\\1.txt", "r", stdin);
#endif
while(~scanf("%d %d%*c", &h, &w))
{
cnt = 1;
rep(i,0,h)
{
rep(j,0,w)
{
scanf("%d%*c", &mp[i][j]);
if(mp[i][j] > 0)
p[cnt++] = NODE(i,j);
}
}
if(-1 == mp[0][0])
{
puts("-1");
continue;
}
p[cnt++] = NODE(0,0);
clc(dis,0);
rep(i,0,cnt)
{
rep(j,i+1,cnt)
{
dis[i][j] = dis[j][i] = bfs(i,j);
}
}
cnt--;
int ALL = (1<<cnt)-1;
clc(dp,0x3f);
clc(dp[0],0);
rep(i,0,cnt) dp[1<<i][i] = dis[0][i];
repe(i,1,ALL)
{
rep(j,0,cnt)//当前在点j
{
if(0 == (1<<j)&i) continue;
rep(k,0,cnt)//来自上一个点k
{
if((1<<k)&i && j != k)
dp[i][j] = min(dp[i][j], dp[i^(1<<j)][k]+dis[k][j]);
}
}
}
int ans = INF;
rep(i,0,cnt) ans = min(ans,dp[ALL][i]+dis[i][cnt]);
if(INF == ans) puts("-1");
else printf("%d\n", ans);
}
return 0;
}