Fix 状态压缩DP HDU 3362

题意:

给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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值