标签:
http://acm.hdu.edu.cn/showproblem.php?pid=4568

2 3 3 3 2 3 5 4 3 1 4 2 1 1 1 3 3 3 2 3 5 4 3 1 4 2 2 1 1 2 2
8 11
/**
hdu 4568 spfa 最短路算法+旅行商问题
题目大意:给定一个n*m的棋盘,每一个格子有一个值,代表经过这个格子的花费,给出sum个宝藏点的坐标,求从棋盘的任意一个边进入棋盘,经过所有的宝藏点后在走出
棋盘所需要的最小花费
解题思路:spfa处理处任意两个宝藏点之间的最短距离(最小花费)和每个宝藏点和边界的最短距离。然后状态压缩:dp[s][i]表示经过宝藏点的状态为s并且结尾点为i的
最小花费
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
const int maxn=205;
int n,m;
struct note
{
int x,y;
} point[15];
int dx[4][2]= {1,0,0,1,-1,0,0,-1};
int dis[maxn][maxn],a[maxn][maxn],dis_border[25],length[20][20];
bool vis[maxn][maxn];
int dp[1<<15][15];
void spfa(int s)
{
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
dis[i][j]=0x3f3f3f3f;
memset(vis,0,sizeof(vis));
queue<pair<int,int> >q;
q.push(make_pair(point[s].x,point[s].y));
vis[point[s].x][point[s].y]=1;
dis[point[s].x][point[s].y]=0;
while(!q.empty())
{
int x=q.front().first;
int y=q.front().second;
q.pop();
vis[x][y]=0;
if(x==0||x==n-1||y==0||y==m-1)
dis_border[s]=min(dis_border[s],dis[x][y]);
for(int i=0; i<4; i++)
{
int xx=x+dx[i][0];
int yy=y+dx[i][1];
if(xx>=0&&xx<n&&yy>=0&&yy<m&&a[xx][yy]!=-1)
{
if(dis[xx][yy]>dis[x][y]+a[xx][yy])
{
dis[xx][yy]=dis[x][y]+a[xx][yy];
if(vis[xx][yy]==0)
{
vis[xx][yy]=1;
q.push(make_pair(xx,yy));
}
}
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
scanf("%d",&a[i][j]);
}
}
int k;
scanf("%d\n",&k);
for(int i=0;i<k;i++)
{
scanf("%d%d",&point[i].x,&point[i].y);
}
//===预处理===
for(int i=0;i<k;i++)
{
dis_border[i]=0x3f3f3f3f;
for(int j=0;j<k;j++)
{
if(i==j)
length[i][j]=0;
else
length[i][j]=0x3f3f3f3f;
}
}
for(int i=0;i<(1<<k);i++)
{
for(int j=0;j<k;j++)
{
dp[i][j]=0x3f3f3f3f;
}
}
//===求有宝藏的点之间和每一个宝藏点和边界的最短距离===
for(int i=0; i<k; i++)
{
spfa(i);
for(int j=0; j<k; j++)
{
if(j==i)continue;
length[i][j]=min(dis[point[j].x][point[j].y],length[i][j]);
}
dp[1<<i][i]=dis_border[i]+a[point[i].x][point[i].y];
}
///===求最优路径===
for(int s=0;s<(1<<k);s++)
{
for(int i=0;i<k;i++)
{
if(s&(1<<i)==0)continue;
if(dp[s][i]==0x3f3f3f3f)continue;
for(int j=0;j<k;j++)
{
if(s&(1<<j)==1)continue;
dp[s|(1<<j)][j]=min(dp[s|(1<<j)][j],dp[s][i]+length[i][j]);
}
}
}
///===还要回到边界==
int ans=0x3f3f3f3f;
for(int i=0;i<k;i++)
{
ans=min(ans,dp[(1<<k)-1][i]+dis_border[i]);
}
printf("%d\n",ans);
}
return 0;
}
标签:
原文地址:http://blog.csdn.net/lvshubao1314/article/details/45845419