HDU 3362 Fix

题目大意:题目给出n(n <= 18)个点的二维坐标,并说明某些点是被固定了的,其余则没固定,要求添加一些边,使得还没被固定的点变成固定的,当一个没固定的点和两个固定了的点连接后,该点就被间接固定了(三角形的稳定性质),无论是直接固定还是间接固定的点,都可以供以后的点用于固定,添加的边的总长度即为代价

题解:观察数据范围,状压Dp可做,对于当前需要固定的点,在已经是固定状态的点中选出两个距离当前点最小的,这就保证了局部最优,从起始状态开始转移,最后判断能否到达最终目标状态就可以了。

#include <cstdio>

#include <algorithm>

#include <cmath>

using namespace std;

int n,x[20],y[20],fix[20];

double dp[1<<18];

double dis(int a,int b){

    return sqrt(1.0*(x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b])*1.0);

}

double F(int pos,int x){

    double ans=0,d[20];

    bool mark[20];

    for(int i=0;i<n;i++){

        if((1<<i)&pos)mark[i]=1,d[i]=dis(i,x);

        else mark[i]=0;

    }

    for(int i=0;i<2;i++){

        double min=1e9;int p=0;

        for(int j=0;j<n;j++)if(mark[j]&&d[j]<min)min=d[j],p=j;

        ans+=min; mark[p]=0;

    }if(ans>=1e9)return -1;

    return ans;

} 

int main(){

    while(scanf("%d",&n),n){

        int begin=0,end=0;

        for(int i=0;i<n;i++){

            scanf("%d%d%d",&x[i],&y[i],&fix[i]);

            if(fix[i])begin+=(1<<i);

            end+=(1<<i);

        }

        for(int i=0;i<(1<<n);i++)dp[i]=1e9;dp[begin]=0;

        for(int i=begin;i<end;i++){

            if(dp[i]==1e9)continue;

            for(int j=0;j<n;j++){

                if(i&(1<<j))continue;

                double sum=F(i,j);

                if(sum>0)dp[i|(1<<j)]=min(dp[i|(1<<j)],dp[i]+sum);

            }

        }

        if(dp[end]==1e9)puts("No Solution");

        else printf("%.6lf\n",dp[end]);

    }return 0;

}

你可能感兴趣的:(HDU)