题意:房间里放着 \(n(n≤15)\) 块奶酪。一只老鼠要把它们都吃掉,最少要跑多少距离?老鼠一开始在 \((0,0)\) 点处。
分析:注意到\(n\)的取值最大只有15,常见的这种量级要么是dfs,要么就是状压DP。考虑状压,用一个变量\(i\)来表示已经走过的点的集合,设\(f[i][j]\)表示已经走过的点的集合为\(i\),当前走到了第\(j\)个点,最少跑动的距离。转移方程也很好写,\(f[i][j]=min(f[i][j],f[i-(1<<j)][k]+dist(x[k+1],y[k+1],x[j+1],y[j+1]))\)即本次从第\(k\)个点走到第\(j\)个点。最后的结果就是\(min(f[s][i]+dist(0,0,x[i+1],y[i+1]))\),其中\(s=2^n\)\(-1\).
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
char ch=getchar();int x=0,f=1;
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int mod=19650827;
const int N=3005;
double x[20],y[20];
double f[35000][20];
double dist(double x1,double y1,double x2,double y2){
return sqrt(1.0*(x1-x2)*(x1-x2)+1.0*(y1-y2)*(y1-y2));
}
int main(){
int n;cin>>n;
for(int i=1;i<=n;++i){
cin>>x[i]>>y[i];
}
memset(f,127,sizeof(f));
for(int i=1;i<(1<<n);++i){
for(int j=0;j<n;++j){
if((i&(1<<j))==0)continue;
if(i==(1<<j)){
f[i][j]=0;continue;
}
for(int k=0;k<n;++k){
if(k==j)continue;
if((i&(1<<k))==0)continue;
f[i][j]=min(f[i][j],f[i-(1<<j)][k]+dist(x[k+1],y[k+1],x[j+1],y[j+1]));
}
}
}
double ans=1e9;
int s=(1<<n)-1;
for(int i=0;i<n;++i){
ans=min(ans,f[s][i]+dist(0,0,x[i+1],y[i+1]));
}
printf("%.2lf\n",ans);
return 0;
}