【题解】洛谷 P1433 吃奶酪

P1433

  • 题目
    • 问题描述
    • 输入格式
    • 输出格式
    • 数据范围
    • 输入/输出例子
      • 输入
      • 输出
      • 说明/提示
  • 解题思路
      • 分析
      • Code
    • 更多方法


题目

原题链接

问题描述

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

输入格式

  • 第一行有一个整数,表示奶酪的数量 n n n
  • 2 2 2 到第 ( n + 1 ) (n + 1) (n+1) 行,每行两个实数,第 ( i + 1 ) (i + 1) (i+1) 行的实数分别表示第 i i i 块奶酪的横纵坐标 x i x_i xi, y i y_i yi

输出格式

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

数据范围

1 ≤ n ≤ 15 , ∣ x i ∣ , ∣ y i ∣ ≤ 200 1≤n≤15,|x_i|, |y_i| \leq 200 1n15xi,yi200

输入/输出例子

输入

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

输出

7.41

说明/提示

对于两个点 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) ( x 2 , y 2 ) (x_2, y_2) (x2,y2)
两点之间的距离公式为 ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 \sqrt{(x_1-x_2)^2+(y_1-y_2)^2} (x1x2)2+(y1y2)2


解题思路

分析

考虑状压DP,定义状态 f i , j f_{i,j} fi,j
当前在 i i i 点,走过的点的状态为 j j j 时的距离。

我们先枚举状态 i i i,再枚举当前节点 j j j,然后枚举由哪个节点 k k k 转移过来的。
需要注意的是:

  1. 由于题目没有规定第一个经过的节点,所以每个节点都可以作为起点。
  2. 算完距离之后,不要忘记加上从 0 0 0 节点到 i i i 节点的距离。
  3. 不要用 memset 给 d o u b l e double double 类型赋初值。
  4. 注意开的空间大小。

处理完这些之后,就是裸的状压DP了,直接套模板即可。

Code

#include
#define int long long
#define IOS ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL);
using namespace std;
const int N=1<<16;
typedef double lf;
int n;
lf x[N],y[N],f[16][N];
lf ga(int i,int j)
{
	lf sum=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
	return sum;
}
signed main()
{
	IOS;
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>x[i]>>y[i];
	for(int i=0;i<=15;i++)
		fill(f[i]+1,f[i]+N,10000);
	for(int i=1;i<(1<<n);i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(i&(1<<(j-1)))
			{
				if(i==(1<<(j-1)))
					f[j][i]=0;
				for(int k=1;k<=n;k++)
					if(k!=j&&((1<<(k-1))&i))
						f[j][i]=min(f[j][i],f[k][i-(1<<(j-1))]+ga(j,k));
			}
		}
	}
	lf ans=1e9;
	for(int i=1;i<=n;i++)
		ans=min(ans,f[i][(1<<n)-1]+ga(0,i));
	cout<<fixed<<setprecision(2)<<ans;
	return 0;
}

更多方法

更多方法

你可能感兴趣的:(C++题解,c++)