题目:
http://acm.hdu.edu.cn/showproblem.php?pid=4568
题意:
n*n的矩阵,每一个格子都有相应的花费,k个宝藏的位置。从任意边界进入任意边界出去。
求出得到所有宝藏的最小花费。
思路:
将边界作为0点。bfs求出宝藏之间以及宝藏与0点的最短距离。
一次TSP,在图中跑一次回路,从起点0回到起点,得到最小花费。
WA点:处理每个宝藏到边界的最短距离,以为走直线就最短,其实不然。可以也在bfs得到最短距离。
AC.
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int a[205][205], d[205][205];
int x[205], y[205], dp[1<<15][15];
bool v[205][205];
struct node {
int x, y, c;
node(int xx, int yy, int cc) {
x = xx; y = yy; c = cc;
}
bool operator <(const node & A) const {
return c > A.c;
}
};
int dx[]={1, -1, 0, 0}, dy[]={0, 0, 1, -1};
int n, m, k;
bool ok(int x, int y)
{
if(x < 0 || y < 0 || x >= n || y >= m || a[x][y] == -1) {
return false;
}
return true;
}
void bfs(int s, int t)
{
priority_queue<node> que;
memset(v, 0, sizeof(v));
que.push(node(x[s], y[s], 0));
v[x[s]][y[s]] = 1;
int c = 0;
while(!que.empty()) {
node e = que.top(); que.pop();
if(e.x == x[t] && e.y == y[t]) {
c = e.c - a[x[t]][y[t]];
}
for(int i = 0; i < 4; ++i) {
int nx = e.x+dx[i], ny = e.y+dy[i];
if(v[nx][ny] || a[nx][ny] == -1)
continue;
if(nx < 0 || ny < 0 || nx >= n || ny >= m) {
d[s][0] = min(d[s][0], e.c);
d[0][s] = min(d[0][s], e.c);
continue;
}
v[nx][ny] = 1;
que.push(node(nx, ny, e.c+a[nx][ny]));
}
}
if(s != t) {
d[s][t] = c;
d[t][s] = c;
}
}
void deal_p_p()
{
memset(d, 0x3f, sizeof(d));
for(int i = 1; i <= k; ++i) {
for(int j = 1; j <= k; ++j) {
//while(!que.empty()) que.pop();
bfs(i, j);
}
}
}
int solve()
{
memset(dp, 0x3f, sizeof(dp));
int nk = k+1;
dp[(1<<nk)-1][0] = 0;
for(int s = (1<<nk)-2; s >= 0; --s) {
for(int v = 0; v < nk; ++v) {
for(int u = 0; u < nk; ++u) {
if(!(s>>u &1)) {
dp[s][v] = min(dp[s][v], dp[s|1<<u][u]+d[v][u]);
}
}
}
}
return dp[0][0];
}
int main()
{
//freopen("in", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
memset(a, 0, sizeof(a));
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
scanf("%d", &a[i][j]);
}
}
int Sum = 0;
scanf("%d", &k);
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
for(int i = 1; i <= k; ++i) {
scanf("%d%d", &x[i], &y[i]);
Sum += a[x[i]][y[i]];
}
deal_p_p();
if(k == 1) {
if(d[1][0] == INF) {
printf("0\n");
}
else printf("%d\n", 2*d[1][0]+a[x[1]][y[1]]);
}
else {
int ans = solve();
if(ans == INF) printf("0\n");
else printf("%d\n", ans+Sum);
}
}
return 0;
}