题目描述
房间里放着n块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在(0,0)点处。
输入输出格式
输入格式:
第一行一个数n (n<=15)
接下来每行2个实数,表示第i块奶酪的坐标。
两点之间的距离公式=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
输出格式:
一个数,表示要跑的最少距离,保留2位小数。
输入输出样例
输入样例#1: 复制
4 1 1 1 -1 -1 1 -1 -1
输出样例#1: 复制
7.41
这题有几个点要注意:
1.直接用dfs是会超时的,还要加入记忆化搜索和剪枝才行
2.对n==0时要特判
3.保留两位小数要记得,最好用printf比较方便
4.已经吃掉的奶酪要记录
5.要把老鼠一开始的位置也看成一个奶酪比较好理解
6.用于记录的数组一定要初始化
7.路程累加了以后一定要归位
讲一下思路:
很简单用dfs配合记忆化搜索和剪枝就能AC了
详细看代码和注释
上AC代码:
#include<iostream>//这个就不用解释了吧
#include<cmath>//sqrt的头文件
#include<cstring>//初始化函数 memset的头文件
#include<cstdio>//用printf输出比较方便(详细看后面)
double ans=1111111111;//存答案
double now=0;//存现在的路程
int n;//同题意
bool book[20];//用于记录
double ax[20];//存储奶酪的x轴的坐标
double ay[20];//存储奶酪的y轴的坐标
void dfs(int dq,int d);//dq代表
double jl[20][20];//记忆化搜索的存储
using namespace std;
int main(){
memset(book,false,sizeof book);//初始化book
memset(jl,0,sizeof jl);//初始化jl
cin>>n;
if(n==0){//对n等于0特判
cout<<0.00;
return 0;//完美结束
}
for(int i=1;i<=n;i+=1){//读入数据
cin>>ax[i];
cin>>ay[i];
}
ax[0]=0;//初始化老鼠的坐标
ay[0]=0;
book[0]=true;//记录一开始的位置已经走过
dfs(0,0);//深搜开始
printf("%0.2lf",ans);//这就是用printf的好处:%0.2lf表示保留两位小数输出double型变量。
return 0;//完美结束
}
void dfs(int dq,int d){
if(now>ans)//这是剪枝,如果当前的路程大于答案就跳出
return;
if(dq==n){//如果吃完了所有奶酪,就判断路程有没有小于答案
if(now<=ans){
ans=now;
}
return;//跳出
}
for(int i=1;i<=n;i+=1){//枚举所有的奶酪
if(book[i]==false){//如果没有被吃掉就从这个点再开始深搜
if(jl[d][i]!=0){//用到了记忆化搜索,这个奶酪到下一个奶酪如果之前又走过就把之前的值拿过来用
book[i]=true;//标记这个奶酪已经被吃掉
now+=jl[d][i];//路程累加
dfs(dq+1,i);//从这个点再开始深搜
book[i]=false;//归位
now-=jl[d][i];//归位
}
else if(jl[i][d]!=0){//同上面,只不过方向不一样
book[i]=true;
now+=jl[i][d];
dfs(dq+1,i);
book[i]=false;
now-=jl[i][d];
}
else{//如果没有走过就只能乖乖算了
book[i]=true;//标记这个奶酪已经被吃掉
jl[i][d]=sqrt((ax[i]-ax[d])*(ax[i]-ax[d])+(ay[i]-ay[d])*(ay[i]-ay[d]));//记录下来这个奶酪到下一个奶酪距离的值
now+=jl[i][d];//路程累加
dfs(dq+1,i);//从这个点再开始深搜
book[i]=false;//归位
now-=jl[i][d];//归位
}
}
}
return;//返回
}