房间里放着 n n n 块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 ( 0 , 0 ) (0,0) (0,0) 点处。
第一行有一个整数,表示奶酪的数量 n n n。
第 2 2 2 到第 ( n + 1 ) (n + 1) (n+1) 行,每行两个实数,第 ( i + 1 ) (i + 1) (i+1) 行的实数分别表示第 i i i 块奶酪的横纵坐标 x i , y i x_i, y_i xi,yi。
输出一行一个实数,表示要跑的最少距离,保留 2 2 2 位小数。
4
1 1
1 -1
-1 1
-1 -1
7.41
对于全部的测试点,保证 1 ≤ n ≤ 15 1\leq n\leq 15 1≤n≤15, ∣ x i ∣ , ∣ y i ∣ ≤ 200 |x_i|, |y_i| \leq 200 ∣xi∣,∣yi∣≤200,小数点后最多有 3 3 3 位数字。
对于两个点 ( x 1 , y 1 ) (x_1,y_1) (x1,y1), ( x 2 , y 2 ) (x_2, y_2) (x2,y2),两点之间的距离公式为 ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 \sqrt{(x_1-x_2)^2+(y_1-y_2)^2} (x1−x2)2+(y1−y2)2。
2022.7.13 2022.7.13 2022.7.13:新增加一组 Hack \text{Hack} Hack 数据。
//90fen
#include
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl "\n"
#define int long long
typedef pair<int,int> PII;
int n,num=0;
double a[16][3],ans=1<<30;
bool vis[16];//记录访没访问过
//两点间距离
double get_dist(double x1, double y1, double x2, double y2){
return sqrt(pow(x1-x2,2)+pow(y1-y2,2));
}
//dfs
void dfs(double x, double y, double dist){
if(dist>ans) return;//剪枝
if(num>=n){//吃完n块奶酪了!
ans=min(ans,dist);
return;
}
//cout<
for(int i=1;i<=n;i++){
if(!vis[i]){
dist+=get_dist(x,y,a[i][1],a[i][2]);
vis[i]=true;
num++;
dfs(a[i][1],a[i][2],dist);
dist-=get_dist(x,y,a[i][1],a[i][2]);//回溯 还原状态
vis[i]=false;
num--;
}
}
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i][1]>>a[i][2];//记录两个点
dfs(0,0,0);//老鼠一开始在 (0,0) 点处
printf("%.2lf",ans);
}
signed main(){
//IOS;
int T=1;
while(T--){
solve();
}
return 0;
}
/*
15
0 0
1 1
1 -1
-1 1
-1 -1
2 2
2 0
2 -2
0 -2
-2 -2
-2 0
-2 2
0 2
1 3
1 4
21.73
*/
状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式
const int N = 16, INF=1e18+10;
int n;
double a[N][3],f[1<<N][N];
//f[i][j]表示第i个状态(哪些吃了,哪些没吃),当前在第j个奶酪所花费的最小代价
double get_dist(double x1,double y1,double x2,double y2){//求两点间距离
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i][1]>>a[i][2];
memset(f,127,sizeof(f));
f[0][0]=0;//起点
for(int i=0;i<1<<n;i++)//枚举状态
for(int j=0;j<=n;j++)//枚举当前在第j个点
for(int k=1;k<=n;k++)//决策:去第k个点
if(!(i&(1<<(k-1))))//判断第k块奶酪还没被吃掉
f[i+(1<<(k-1))][k]=min(f[i+(1<<(k-1))][k],f[i][j]+get_dist(a[j][1],a[j][2],a[k][1],a[k][2]));
double res=INF;
for(int i=1;i<=n;i++)
res=min(res,f[(1<<n)-1][i]);
printf("%.2lf",res);
}