Description
There are a few points on a plane, and some are fixed on the plane, some are not. We want to connect these points by some sticks so that all the points are fixed on the plane. Of course, we want to know the minimum length of the sum of the sticks.
As in the images, the black points are fixed on the plane and red ones are not, which need to be fixed by sticks.
All the points in the left image have been fixed. But the middle one is not, which we need add one stick to fix those four points (the right image shows that stick). Triangle is steady, isn’t it?
Input
The input consists of multiply test cases. The first line of each test case contains one integer, n (1 <= n <= 18), which is the number of points. The next n lines, each line consists of three integers, x, y, c (0 <= x, y < 100). (x, y) indicate the coordinate of one point; c = 1 indicates this point is fixed; c = 0 indicates this point is not fixed. You can assume that no two points have the same coordinate.
The last test case is followed by a line containing one zero, which means the end of the input.
output
Output the minimum length with six factional digits for each test case in a single line. If you cannot fix all the points, then output “No Solution”.
Hint
大概意思就是给你一些点,其中一些点是固定的,然后还有一些没有固定的,然后问你固定所有点所用的线段的最小长度是多少。
所谓固定,就是形如三角形的情况,就是两个固定的点向一个未固定的点连两条边,就能把未固定的点固定。
分析
其实大概的状压dp都很容易打出来,就是
2n∗n∗n∗n
的暴力:
枚举状态,枚举两个连接点,枚举中间点,更新。
然而这样会超时。。
比赛时我就是这样打的,所以我便爆0了。。
后来lihui和我说可以只枚举中间点,然后选两个离中间点(中间点,即要使它变为固定点的点)最近的点,更新就可以了。。。
时间复杂度为
2n∗n∗n
一阵沉默。。。。
我一直没想到的原因是我没有跳开循环的顺序,一直想的时候默认了一定要枚举两个连接点。。。
脑洞还是不够开啊!要拓宽思路,不要老想一点,在想不到时要多出去走走,然后每一个细节都要注意,看看是否是必要的,还要多换角度思考。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=20;
int n;
struct node{
int x,y,z;
}a[N];
struct note{
double a;int b;
}q[N][N];
double f[1<<N],op;
int e[N],cnt[1<<N],cn[1<<N],i,j,k,l;
double sqr(double x){return x*x;}
bool cmp(note x,note y){
return x.a<y.a;
}
int main(){
scanf("%d\n",&n);
int ted=0;
while(n){
int tot=0,sum=0;
for(i=1;i<=n;i++){
scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].z);
if (a[i].z) tot+=1<<(i-1),sum++;}
ted++;
if (sum<2) {
double k=0;
if (n==sum)printf("%.6lf\n",k);else printf("No Solution\n");
scanf("%d\n",&n);
continue;
}
if (sum==n) {
double k=0;
printf("%.6lf\n",k);
scanf("%d\n",&n);
continue;
}
for(i=0;i<=n;i++) e[i]=1<<i;
memset(f,127,sizeof(f));
memset(q,0,sizeof(q));
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
q[i][j].a=sqrt(sqr(a[i].x-a[j].x)+sqr(a[i].y-a[j].y));
q[i][j].b=j;
}
sort(q[i]+1,q[i]+n+1,cmp);
}
op=f[1];f[tot]=0;
int te=(1<<n)-1;
for(i=tot;i<=te;i++)
if (f[i]!=op)
{
for(l=1;l<=n;l++)
if (!(i&(1<<(l-1)))){
int oi=0;double u=0;
for(j=1;j<=n;j++)
if (i&(1<<(q[l][j].b-1))) {
oi++;
u+=q[l][j].a;
if (oi==2) {f[i+e[l-1]]=min(f[i+e[l-1]],f[i]+u);
break;
}
}
}
}
printf("%.6lf\n",f[te]);
scanf("%d\n",&n);
}
}