洛谷P1433吃奶酪(正向暴力递归,回溯更新)

题目链接:https://www.luogu.org/problemnew/show/P1433#sub

这道题就是正向递归暴力找到所有情况,取最小值!(写出来跟全排列很像,主要是因为回溯更新,暴力所有情况找到最小的)

两个坑点:

1.递归反复开方很耗时间,需要预处理两点距离。

2.优化剪枝,如果当前走的距离已经超过上一个最小值,再走下去肯定大于,所以返回

刚开始没有剪枝优化,T了4点。。。

 1 #include <iostream>
 2 #include <string>
 3 #include <algorithm>
 4 #include <iomanip>
 5 #include <vector>
 6 #include <cstdio>
 7 #include <cstring>
 8 #include <cmath>
 9 using namespace std;
10 typedef long long ll;
11 typedef unsigned long long ull;
12 const int maxn=1e6+5;
13 int vis[maxn];
14 double dis[2005][2005];
15 int n,m;
16 double ans=1e9*1.0;
17 struct px
18 {
19     double x;
20     double y;
21 }T[maxn];
22 int f=0;
23 
24 void so(int last,double sum,int step)//上一个点,走的距离,吃了几个点
25 {
26     if(step==n)
27     {
28         ans=min(ans,sum);
29         //cout<<++f<<' '<<setiosflags(ios::fixed)<<setprecision(2)<<ans<<endl;//便于观察结果
30         return;
31     }
32 
33     for(int i=1;i<=n;i++)
34     {
35         if(vis[i]==0)
36         {
37             //cout<<i<<' '<<last<<' '<<i<<' '<<dis[last][i]<<endl;//便于观察结果
38             vis[i]=1;
39             so(i,sum+dis[last][i],step+1);
40             vis[i]=0;
41         }
42     }
43 }
44 
45 int main()
46 {
47     ios::sync_with_stdio(false); cin.tie(0);
48 
49     cin>>n;
50     for(int i=1;i<=n;i++) cin>>T[i].x>>T[i].y;
51 
52     for(int i=0;i<=n;i++)
53     {
54         for(int j=0;j<=n;j++)
55         {
56             dis[i][j]=sqrt((T[i].x-T[j].x)*(T[i].x-T[j].x)+(T[i].y-T[j].y)*(T[i].y-T[j].y));
57         }
58     }
59 
60     so(0,0,0);
61 
62     cout<<setiosflags(ios::fixed)<<setprecision(2)<<ans<<endl;
63 
64     return 0;
65 }

优化剪枝后

 1 #include <iostream>
 2 #include <string>
 3 #include <algorithm>
 4 #include <iomanip>
 5 #include <vector>
 6 #include <cstdio>
 7 #include <cstring>
 8 #include <cmath>
 9 using namespace std;
10 typedef long long ll;
11 typedef unsigned long long ull;
12 const int maxn=1e6+5;
13 int vis[maxn];
14 double dis[2005][2005];
15 int n,m;
16 double ans=1e9*1.0;
17 struct px
18 {
19     double x;
20     double y;
21 }T[maxn];
22 int f=0;
23 
24 void so(int last,double sum,int step)//上一个点,走的距离,吃了几个点
25 {
26     //if(sum>=ans) return;优化剪枝
27     if(step==n)
28     {
29         ans=min(ans,sum);
30         //cout<<++f<<' '<<setiosflags(ios::fixed)<<setprecision(2)<<ans<<endl;//便于观察结果,比如递归到这了几次,观察剪枝效果
31         return;
32     }
33 
34     for(int i=1;i<=n;i++)
35     {
36         if(vis[i]==0)
37         {
38             //cout<<i<<' '<<last<<' '<<i<<' '<<dis[last][i]<<endl;//便于观察结果,比如递归到这了几次,观察剪枝效果
39             if(sum+dis[last][i]>=ans) break;//这次放到这里剪枝优化效果比放到上面好,直接退出62ms
40             vis[i]=1;
41             so(i,sum+dis[last][i],step+1);
42             vis[i]=0;
43         }
44     }
45 }
46 
47 int main()
48 {
49     ios::sync_with_stdio(false); cin.tie(0);
50 
51     cin>>n;
52     for(int i=1;i<=n;i++) cin>>T[i].x>>T[i].y;
53 
54     for(int i=0;i<=n;i++)
55     {
56         for(int j=0;j<=n;j++)
57         {
58             dis[i][j]=sqrt((T[i].x-T[j].x)*(T[i].x-T[j].x)+(T[i].y-T[j].y)*(T[i].y-T[j].y));
59         }
60     }
61 
62     so(0,0,0);
63 
64     cout<<setiosflags(ios::fixed)<<setprecision(2)<<ans<<endl;
65 
66     return 0;
67 }

完。

原文地址:https://www.cnblogs.com/redblackk/p/9816730.html