洛谷 [P1433 吃奶酪] {搜索|DFS|状态压缩} 奋斗的珂珂~

题目描述

房间里放着 n块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 (0,0) 点处。

输入格式
第一行有一个整数,表示奶酪的数量 n。

第 2 到第 (n + 1) 行,每行两个实数,第 (i + 1)行的实数分别表示第 i 块奶酪的横纵坐标xi,yi。

输出格式

输出一行一个实数,表示要跑的最少距离,保留 2 位小数。

输入输出样例

输入
4
1 1
1 -1
-1 1
-1 -1
输出
7.41

说明/提示

数据规模与约定
对于全部的测试点,保证 1≤n≤15,∣xi∣,∣yi∣≤200,小数点后最多有 3 位数字。

提示
对于两个点 (x1,y1),(x2, y2)(x2,y2),两点之间的距离公式为在这里插入图片描述

完整代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=30;
int m;
double ans=1e9;//记录最短路径长度 
int show[maxn];//记录该奶酪是否已经吃过 
double lens[maxn][maxn];//lens[i][j]记录第i个点到第j的点的距离
double a[maxn][2];//记录奶酪的坐标
double  dp[1<<15][maxn];//状态压缩,第一个下标代表已经吃到的奶酪,1代表已经吃到,0代表没有吃到
                     //第二个下标代表当前奶酪的位置

void dfs(int n,int state,int number,double sum)
{//eg:state=10010,代表吃了第二个和第五个奶酪(从右往左) 
	if(number==m+1)
	{
		ans=min(sum,ans);
		return ;
	}
	
	for(int g=1;g<=m;g++)
	{
		if(!show[g])//如果没有出现过 
		{
			int nowstate=state+(1<<(g-1));
			if(dp[nowstate][g])//如果之前状态有值 
			{
				if(dp[nowstate][g]<=sum+lens[n][g])//之前状态的值小于现在状态则不再需要处理了,相当于剪枝 
				 continue;
			}
			show[g]=1;
			dp[nowstate][g]=sum+lens[n][g];//更新当前状态的值 
			dfs(g,nowstate,number+1,dp[nowstate][g]);
			show[g]=0;
		}
	}
	return;
}
int main()
{
	scanf("%d",&m);
	a[0][0]=0;
	a[0][1]=0;//原点的坐标
	for(int i=1;i<=m;i++)
	{
		scanf("%lf %lf",&a[i][0],&a[i][1]);
	 } 
	 
	//计算第i个点到达第j个点的长度
	for(int i=0;i<=m;i++)
	{
		for(int j=i+1;j<=m;j++)
		{
			double lenx=a[i][0]-a[j][0];
			double leny=a[i][1]-a[j][1];
			lens[i][j]=sqrt(lenx*lenx+leny*leny);
			lens[j][i]=lens[i][j]; 		
		}
	 } 
	
	dfs(0,0,1,0);//第一个参数表示当前走的是第几个奶酪,第二个参数代表当前状态压缩表示吃到的奶酪的状态
	             //第三个参数-1代表当前吃到的奶酪个数,第四个参数代表当前距离的值 
	printf("%.2f",ans);
	return 0; 	 
 } 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值