洛谷 普及组 P1433 吃奶酪

题目描述

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

输入格式

第一行一个正整数n。

接下来每行2个实数,表示第i块奶酪的坐标。

两点之间的距离公式为\sqrt{(x_{1}-x_{2})^{2}+(y_{1}-y_{2})^{2}}

输出格式

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

数据范围

1 ≤ n ≤ 15

输入输出样例

  输入

4
1 1
1 -1
-1 1
-1 -1

  输出

7.41

思路

一开始偷懒采用DFS,结果最后一个测试点怎么都会超时,于是学了状态压缩动态规划(状压DP)

▶用状压DP解决题目得先明白位运算。针对这道题简单地讲,<<是左移运算符。假设x=2,那么x<<1相当于x的二进制10后面补一个0,变成100,十进制下是4。所以<<是十进制下乘以2的意思

▶在这道题中,我们采用二进制来表示某个点的奶酪吃过了没,1表示吃过,0表示还没吃。样例中有4块奶酪,那么一开始就是0000,4块吃完后就是1111。0000~1111包含所有奶酪食用的情况(16种)。我们知道二进制下1111=10000-1,十进制就是2^{4}-1,用<<表示就是(1<<4)-1。n块奶酪呢?那就是(1<用这个式子就能表示所有奶酪的状况

▶接下来需要知道&(与运算符),只有1&1时才等于1,其余情况=0;要判断某状态下第 i 块奶酪吃过没,就要判断二进制的第 i 位是否为0,用 if( ( (1<<( i−1) ) & x ) ==0),假设当前状态是x=0011,从右往左数第1、2位是1,如果要判断第3位是否为0,可以写作 if( ( ( 1<<( 3-1) ) & x ) ==0),也就是100 & 0011,结果是0000,说明第3位是0,因为第3位上1&0=0

▶然后是状态转移方程:

l[now][r] = min(l[now][r], l[pre][r-(1<<(now-1))]+dis(pre,now));

 

洛谷 普及组 P1433 吃奶酪_第1张图片

 ▶最后只需遍历1到n,看从哪个点开始得到的路线最短,加上从原点(0,0)到这个点的距离dis(0,i)即可

#include
#include
#include
#include
using namespace std;
int n;
double x[16], y[16], l[16][100000]; //l[p][r]数组是点p在某种状况r下的最短路线
double dis(int a, int b) {return sqrt( (x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]) );}
void DP()
{
	for(int i = 1; i <= n; i++) l[i][1<<(i-1)] = 0; //点到自身的距离为0
	for(int r = 1; r <= (1<> n;
	for(int i = 1; i <= n; i++) cin >> x[i] >> y[i];
	memset(l, 127, sizeof(l)); //初始化点在各种状况下的距离
	DP();
	double mindis = 0x3f3f3f3f; //初始化为很大的数
	for(int i = 1; i <= n; i++) 
		if(l[i][(1<

memset(a,127,sizeof(a))表示将a数组的全部元素设置成一个非常大的数2139062143,不是数字127。

你可能感兴趣的:(洛谷刷题日记)