zoukankan      html  css  js  c++  java
  • 2014 Super Training #1 B Fix 状压DP

    原题: HDU 3362 http://acm.hdu.edu.cn/showproblem.php?pid=3362

    开始准备贪心搞,结果发现太难了,一直都没做出来。后来才知道要用状压DP。

    题意:题目给出n(n <= 18)个点的二维坐标,并说明某些点是被固定了的,其余则没固定,要求添加一些边,使得还没被固定的点变成固定的,可见题目中的图形sample。

    由于n很小,而且固定点的顺序没有限制,所以需要用状态压缩DP。

    注意:
    1.当一个没固定的点和两个固定了的点连接后,该点就被(间接)固定了(三角形的稳定性质)
    2.被固定的点还可以用来固定别的点

    因此,对于当前需要固定的点,在已经是固定状态的点中选出两个距离当前点最小的,这就保证了局部最优,从起始状态开始转移,最后判断能否到达最终目标状态就可以了。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define Mod 1000000007
    using namespace std;
    #define N 100007
    
    struct Point
    {
        double x,y;
        int f;
    }p[22];
    double dp[1<<20];
    int unfix[21];
    double dis[20];
    int n;
    
    double Dis(int i,int j)
    {
        Point ka = p[i];
        Point kb = p[j];
        return (double)sqrt((ka.x-kb.x)*(ka.x-kb.x)+(ka.y-kb.y)*(ka.y-kb.y));
    }
    
    double Fixit(int state,int tofix)
    {
        int i = 0,j;
        int tmp = state;
        memset(dis,0,sizeof(dis));
        while(i < n)
        {
            if(tmp & 1)  //已固定点
            {
                unfix[i] = 0;
                dis[i] = Dis(tofix,i);
            }
            else
                unfix[i] = 1;
            i++;
            tmp >>= 1;
        }
        double mini_1 = Mod;
        int tag = -1;
        for(i=0;i<n;i++)   //选第一个点
        {
            if(!unfix[i])  //fixed
            {
                if(dis[i] < mini_1)
                {
                    mini_1 = dis[i];
                    tag = i;
                }
            }
        }
        double mini_2 = Mod;
        for(i=0;i<n;i++)   //选第二个点
        {
            if(i == tag)   //选过
                continue;
            if(!unfix[i])
            {
                if(dis[i] < mini_2)
                    mini_2 = dis[i];
            }
        }
        if(mini_1+mini_2 >= Mod)
            return -1;
        return mini_1+mini_2;
    }
    
    int main()
    {
        int i,j;
        int Na;
        while(scanf("%d",&n)!=EOF && n)
        {
            int S = 0;
            Na = (1<<n)-1;
            for(i=0;i<n;i++)
            {
                scanf("%lf%lf%d",&p[i].x,&p[i].y,&p[i].f);
                if(p[i].f)
                    S |= (1<<i);
            }
            for(i=0;i<=Na;i++)
                dp[i] = Mod;
            dp[S] = 0;
            for(i=S;i<Na;i++)
            {
                if(dp[i] == Mod)
                    continue;
                for(j=0;j<n;j++)  //选一个unfix的点固定
                {
                    if(i & (1<<j)) //已fix,跳过
                        continue;
                    double delta = Fixit(i,j);
                    if(delta == -1)
                        continue;
                    else  //更新固定完这个点后的最少花费
                        dp[i|(1<<j)] = min(dp[i|(1<<j)],dp[i]+delta);
                }
            }
            if(dp[Na] == Mod)
                puts("No Solution");
            else
                printf("%.6lf
    ",dp[Na]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    java设计模式
    漏桶算法工具类
    http请求requestUtils
    去掉字符串中特殊符号造成的空格
    java 分布式id生成算法
    java枚举
    java 32个Java面试必考点
    配置tomcat下war包可以自压缩
    tomcat (选号)公司tomcat无页面解决
    docker 12 docker容器数据卷
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3812714.html
Copyright © 2011-2022 走看看