洛谷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 }
完。