观察题目,发现我们只关心初始点和坚果所在的位置,而坚果数量,所以启发我们可以用状态压缩dp来做,再继续思考,此时题目转化为给定起始点,要求我们经过其他所有点恰好一次,并最终返回起始点,问最短路径,它与P1171完全一样,思考P1171的解题方法:记表示从起始点走到,此时走过的点集状态为的最短路径,答案即
因此我们只要求出数组,答案就出来了。这道题我们可以向八个方向移动,因此其实就是切比雪夫距离,是横纵坐标差的最大值,而不是曼哈顿距离。具体实现见代码:
#include<bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define x first
#define y second
const int N=25,M=(1<<16)+10,INF=0x3f3f3f3f;
int n,m,dis[N][N],tot,f[N][M];
PII q[N];
char ch[N][N];
int main(){
while(~scanf("%d%d",&n,&m)){
tot=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>ch[i][j];
if(ch[i][j]=='L') q[1]=make_pair(i,j);
else if(ch[i][j]=='#') q[++tot]=make_pair(i,j);
}
}
for(int i=1;i<=tot;i++){
for(int j=i+1;j<=tot;j++){
int a=abs(q[i].x-q[j].x),b=abs(q[i].y-q[j].y);
dis[i][j]=dis[j][i]=max(a,b);
}
}
memset(f,0x3f,sizeof(f));
f[1][1]=0;
for(int i=0;i<(1<<tot);i++){
for(int k=1;k<=tot;k++){
if((1<<k-1)&i){
for(int j=1;j<=tot;j++){
if((1<<j-1)&i) continue;
f[j][i|(1<<j-1)]=min(f[j][i|(1<<j-1)],f[k][i]+dis[k][j]);
}
}
}
}
int ans=INF;
for(int i=2;i<=tot;i++) ans=min(ans,f[i][(1<<tot)-1]+dis[i][1]);
if(tot<2) cout<<0<<endl;//特判没有坚果的情况
else cout<<ans<<endl;
}
return 0;
}