链接:点击打开链接
题意:有一个n*m的棋盘,每一个格子有一个值,代表经过这个格子的花费,给出k个宝藏点的坐标,求从棋盘的任意一个边进入棋盘,经过所有的宝藏点后在走出棋盘所需要的最小花费
代码:
#include <queue>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int dp[1<<15][15];
int v[505],str[505][505],vis[505][505],num[505][505],dis[505][505];
struct node{
int x,y,sum;
friend bool operator<(node a,node b){
return a.sum>b.sum;
}
};
int n,m,k;
int p[205],q[205];
int xx[]={1,0,-1,0};
int yy[]={0,-1,0,1};
void bfs(node st,int ss){
priority_queue<node>que;
int i,cnt;
node cur,temp;
cnt=0;
que.push(st);
memset(v,0,sizeof(v));
memset(vis,0,sizeof(vis));
v[ss]=1;
vis[st.x][st.y]=1;
while(que.size()){
cur=que.top();
que.pop();
vis[cur.x][cur.y]=1;
if(!v[0]&&(cur.x==1||cur.x==n||cur.y==1||cur.y==m)){
cnt++;
v[0]=1;
dis[ss][0]=cur.sum;
dis[0][ss]=cur.sum+str[p[ss]][q[ss]];
if(cnt==k)
return;
} //因为bfs用的优先队列因此第一次遇到的边界一定是最近的
if(num[cur.x][cur.y]!=-1)
if(v[num[cur.x][cur.y]]==0){
cnt++;
v[num[cur.x][cur.y]]=1;
dis[ss][num[cur.x][cur.y]]=cur.sum;
if(cnt==k)
return;
} //记录宝藏间的距离
for(i=0;i<4;i++){
temp.x=cur.x+xx[i];
temp.y=cur.y+yy[i];
if(temp.x>=1&&temp.x<=n&&temp.y>=1&&temp.y<=m)
if(str[temp.x][temp.y]!=-1&&vis[temp.x][temp.y]!=1){
temp.sum=cur.sum+str[temp.x][temp.y];
vis[temp.x][temp.y]=1;
que.push(temp);
}
}
}
}
int main(){ //如果不考虑进出图的问题也就是边界的情况,那么
int i,j,t,s,pp,qq; //就是一个裸的TSP,但是有边界所以我们可以把边界
node st; //也算作一个点,只要求出k+1个点两两的距离就可以
scanf("%d",&t); //转换为裸的TSP
while(t--){
scanf("%d%d",&n,&m);
memset(num,-1,sizeof(num));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&str[i][j]);
scanf("%d",&k);
for(i=0;i<=k;i++)
for(j=0;j<=k;j++){
if(i==j)
dis[i][j]=0;
else
dis[i][j]=INF;
}
for(i=1;i<=k;i++){
scanf("%d%d",&p[i],&q[i]);
p[i]++,q[i]++;
num[p[i]][q[i]]=i;
} //记录宝藏的位置
for(i=1;i<=k;i++){
st.x=p[i],st.y=q[i],st.sum=0;
bfs(st,i);
} //求出两两的距离
memset(dp,INF,sizeof(dp));
dp[(1<<(k+1))-1][0]=0;
for(s=(1<<(k+1))-1;s>=0;s--){
for(pp=0;pp<k+1;pp++){
for(qq=0;qq<k+1;qq++){
if(!(s&(1<<qq)))
dp[s][pp]=min(dp[s][pp],dp[s|(1<<qq)][qq]+dis[pp][qq]);
}
}
}
if(dp[0][0]>=INF)
puts("0");
else
printf("%d\n",dp[0][0]);
}
return 0;
}