洛谷 / 题目列表 / 题目详情
P1433 吃奶酪
提交
23.28k
通过
9.30k
时间限制
1.00s
内存限制
125.00MB
题目描述
房间里放着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
···
/*
预处理一下各个点之间的距离,
暴搜可以过。
但是!!
这是经典的NP问题,
数据比较小,用状压dp,d它!!!!
*/
第一种写法:
虚拟一个终点(原来的终点到它的距离为0,
记的起点(0,0)到其他点的距离要算上),
就相当于前几天写的:最短Hamilton路径(状压dp)
#include <bits/stdc++.h>
using namespace std;
const int N = 1<<20;
double dp[N][20];
struct Point
{
double x,y;
} p[20];
double getDis(int i,int j)
{
return sqrt(pow(p[i].x-p[j].x,2)+pow(p[i].y-p[j].y,2));
}
double dis[20][20];
int n;
void init()
{
for(int i = 0; i <= n; i++)
{
for(int j = i; j <= n; j++)
{
dis[i][j] = dis[j][i] = getDis(i,j);
}
}
int t = n+2;
for(int i = 0; i < (1<<t); i++)
{
for(int j = 0; j < t; j++)
{
dp[i][j] = 1e16;
}
}
dp[1][0] = 0;
}
int main()
{
cin>>n;
p[0].x = p[0].y = 0;
for(int i = 1; i <= n; i++)
{
cin>>p[i].x>>p[i].y;
}
init();
n = n+2;//原来起点(0,0),还有虚拟了一个(原来所有终点的)终点
for(int i = 1; i < (1<<n); i++)
{
for(int j = 0; j < n; j++)
{
if((i>>j)&1)
for(int k = 0; k < n; k++)
{
dp[i][j] = min(dp[i][j],dp[i-(1<<j)][k]+dis[k][j]);
}
}
}
cout.precision(2);
cout<<fixed<<dp[(1<<n)-1][n-1]<<endl;
return 0;
}
为了更深入了解状压dp,
第二种写法,不虚拟终点,
最终对所有终点的求个最小值
(时间,空间复杂度都更优)
#include <bits/stdc++.h>
using namespace std;
const int N = 1<<17;
double dp[N][17];
struct Point
{
double x,y;
} p[17];
double getDis(int i,int j)
{
return sqrt(pow(p[i].x-p[j].x,2)+pow(p[i].y-p[j].y,2));
}
double dis[17][17];
int n;
void init()
{
for(int i = 0; i <= n; i++)
{
for(int j = i; j <= n; j++)
{
dis[i][j] = dis[j][i] = getDis(i,j);
}
}
int t = n+1;
for(int i = 0; i < (1<<t); i++)
{
for(int j = 0; j < t; j++)
{
dp[i][j] = 1e16;
}
}
dp[1][0] = 0;
}
int main()
{
cin>>n;
if(!n)
{
cout<<"0.00"<<endl;
return 0;
}
p[0].x = p[0].y = 0;
for(int i = 1; i <= n; i++)
{
cin>>p[i].x>>p[i].y;
}
init();
n = n+1;
for(int i = 1; i < (1<<n); i++)
{
for(int j = 1; j < n; j++)
{
if((i>>j)&1)
for(int k = 0; k < n; k++)
{
dp[i][j] = min(dp[i][j],dp[i-(1<<j)][k]+dis[k][j]);
}
}
}
double ans = 1e16;
for(int i = 1; i < n; i++)
ans = min(ans,dp[(1<<n)-1][i]);
cout.precision(2);
cout<<fixed<<ans<<endl;
return 0;
}