吃奶酪

洛咕

题意:房间里放着 \(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;
}

posted on 2022-07-19 10:51  PPXppx  阅读(108)  评论(0编辑  收藏  举报