原题链接:
P1433 吃奶酪 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
算法 思路:
这个题的大意就是让我们从00点出发,遍历所有点,求一个最短路径,这不是一个图的问题,因为边是任意的,所以会首先想到dfs搜索就行了,
剪枝:使用一个ans保留过程中的答案,如果某条道路还没走完就已经比结果大了,直接返回。
当做到这一步时,会发现有案例会TLE,说明还要进一步剪枝。
需要考虑:同样的几个点, 例如 1 3 5 , 从 0 到 1 3 5 ,从 0 到 3 5 1....都是道路,但是这些道路里面有长的有短的,我们不要每次都要走一遍,所以就要保存一个每个具体道路的最短路。具体的方法是通过:状态压缩 来 保存。
具体解释可见:P1433 吃奶酪题解 - 糖豆爸爸 - 博客园 (cnblogs.com)
AC Code:
#include<bits/stdc++.h>
using namespace std;
const int N =16;
double pt[N][2];
int v[N];
int n;
double ans = DBL_MAX;
double dp[1<<N][N];
double dis[N][N];
void dfs(int k,double temp,int f,int pass){
if(temp>ans)return;
if(k==n){
ans =min(ans,temp);
return;
}
for(int i =1;i<=n;i++){
int tt = pass+ (1<<(i-1));
double d = dis[i][f];
if(dp[tt][i] && dp[tt][i]<= temp+d)continue;
if(!v[i]){
v[i] = 1;
dp[tt][i] = temp+ d;
dfs(k+1,temp+d,i,tt);
v[i] =0;
}
}
}
int main(){
cin>>n;
for(int i =1;i<=n;i++)cin>>pt[i][0]>>pt[i][1];
for(int i =0;i<=n;i++)
for(int j =i+1;j<=n;j++)
dis[i][j] = dis[j][i] = sqrt(pow(pt[i][0]-pt[j][0],2)+pow(pt[i][1]-pt[j][1],2));
dfs(0,0.0,0,0);
printf("%.2f",ans);
return 0;
}