题意:
给n个点(n<=18),有些点固定了,有些点没固定。每个点都有坐标,目标是把所有点都固定住,一个未固定的点至少要跟两个点相连才算被固定。
题解:
由于n不大,所以可以用二进制位表示该点是否被固定,一遍DP即可。
代码:
int main(int argc, char** argv)
{
int i,j,m,x,y,sum;
double l1,l2;
while(scanf("%d",&n)!=EOF)
{
if ((n==0)) break;
sum=0;
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c);
sum+=a[i].c;
}
if (sum<=1)
{
if (n-sum>=1)
{printf("No Solution/n");continue;}
else {printf("0.000000/n");continue;}
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
dis[i][j]=sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
for(i=0;i<(1<<n);i++) dp[i]=1e100;
dp[0]=0;
ql=fl=0;
for(i=1;i<=n;i++)
if (a[i].c==0)
qq[++ql]=i;
else fq[++fl]=i;
// if ((fl<=1)&&(ql>=1)) {printf("No Solution/n");continue;}
for(i=0;i<(1<<ql);i++)
{
for(j=1;j<=ql;j++)
{
if ( (i&(1<<(j-1))) ) continue;
l1=l2=1e100;
for(int k=1;k<=ql;k++)
if ((1<<(k-1))&i)
{
if (dis[qq[j]][qq[k]]<l1)
{
l2=l1;
l1=dis[qq[j]][qq[k]];
}
else
if (dis[qq[j]][qq[k]]<l2)
{
l2=dis[qq[j]][qq[k]];
}
}
for(int k=1;k<=fl;k++)
{
if (dis[qq[j]][fq[k]]<l1)
{
l2=l1;
l1=dis[qq[j]][fq[k]];
}
else
if (dis[qq[j]][fq[k]]<l2)
{
l2=dis[qq[j]][fq[k]];
}
}
dp[i|(1<<(j-1))]=min(dp[i|(1<<j-1)],dp[i]+l1+l2);
}
}
printf("%.6lf/n",dp[(1<<ql)-1]);
}
return 0;
}