去吧,皮卡秋 | ||||||
| ||||||
Description | ||||||
“喏,解出来了。秘密是啥?”小果问。 小粒满脸欢喜,“小果你好棒啊!” “秘密到底是啥?” “秘密就是:本天才不会……” =。=||| 小果听完这个秘密,啪…… 小粒飞出了10米远。 小果看着楼下的雪堆,对小粒说:“你看,这下面有N个雪堆,你什么时候给每个雪堆都插上小红旗,我就扰了你” 小粒说:“大恩不言谢,我这就去” “等等,你想先去哪个?”“这个吧”“送你一程。”啪…… 已知小粒可以选择任意一个雪堆作为起点,现问小粒最少要跑多少距离,才能在每个雪堆上都插上小红旗? | ||||||
Input | ||||||
第一行一个整数,表示测试组数t。 每组第一行一个正整数N(1<=N<=15),表示点的个数。 接下来n行,每行两个整数xi,yi(0<=xi,yi<=100),表示点的坐标。 | ||||||
Output | ||||||
求出连接n个点的最短路径长度。结果保留两位小数。 | ||||||
Sample Input | ||||||
3 3 0 0 0 1 0 2 3 0 0 0 1 1 0 4 0 0 1 0 2 0 1 1 | ||||||
Sample Output | ||||||
2.00 2.00 3.41 | ||||||
Hint | ||||||
红色样例中,小粒的一种可能走法为(0,0)->(1,0)->(2,0)->(1,1) | ||||||
Source | ||||||
"尚学堂杯"哈尔滨理工大学第五届程序设计团队赛(预选) |
冬季校团队赛的一个热身赛的题,当时因为还是比较年轻,毕竟接触ACM也才不到四个月,带着最短路和最小生成树的思维一顿乱敲,怎么敲都是不过,也算是最近要学习状压dp,所以最近想起来这个题,做完了来写发题解。
思路:建设dp【i】【j】数组,表示i状态要终点是j的最短距离。构建思路是这样的:
要从i状态变成q状态,无非要从i状态中找一个点j,然后在q状态中找到一个点k,从j走到k。
辣么状态转移方程不难推出:
dp【q】【k】=min(dp【q】【k】,dp【i】【j】+dis【j】【k】)其中q一定是从i+(1 <<k)来的。
整个状态转移方程其实就是在表示从i状态中找一个点j,再选一个i状态中没有走过的点k,从j走到k。
辣么要从i状态变成q状态之前呢,要满足这样两个条件:
1、i状态里边有j这个点,才能把j这个点确定下来,辣么我们要怎样确定i状态有没有j这个点呢?根据位运算里边&运算符的操作规则:同1为1,其余为0的特性,我们就可以用
i&(1<<j)判断其值是否为0即可,如果为0,表示i状态中没有走过j(也就是i状态中没有j这个点),如果不为0,那么就表示有。
2、i状态里边没有k这个点,才能把k这个点确定下来,判断方法同上。
注意的点:位运算优先级很难记,不妨在有位运算的地方都加上括号。
AC代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<math.h>
using namespace std;
double dp[1<<17][17];
int x[20];
int y[20];
double dis(int i, int j)//计算距离
{
return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d%d",&x[i],&y[i]);
}
memset(dp,0x7f,sizeof(dp));
int end=1<<n;
for(int i=0;i<n;i++)//初始化起点.
{
dp[1<<i][i]=0;
}
for(int i=0;i<end;i++)
{
for(int j=0;j<n;j++)
{
if (!(i&(1<<j))) continue;//如果i中没有j,辣么不合法
for(int k=0;k<n;k++)
{
if (i&(1<<k)) continue;//如果i中有j,辣么也不合法
int q=(i+(1<<k));
if(dis(j,k)+dp[i][j]<dp[q][k])
{
dp[q][k]=dis(j,k)+dp[i][j];//状态转移方程
}
}
}
}
double ans=1e300;//千万记住这里要开大值,我开小了wa了,看了别人代码才知道这块一定要大。
for(int i=0;i<n;i++)
{
ans=min(ans,dp[end-1][i]);
}
printf("%.2lf\n",ans);
}
}