• HDU 3920 Clear All of Them I(状压DP)题解


    题意:2n个点,一个起点,开n枪,每枪必须打两个点,花费为起点到其中一点距离加上两点距离。问打完2n个点的最小花费。

    思路:很显然应该dp状态,然后枚举i j两个空位置去填,那么复杂度$O(20 * 20 * n^{20})$,这个会超时。因为内存限制不能预处理每个状态的子状态。所以我们要想办法减少复杂度。显然复杂度多在重复枚举的过程,因为花费之和与枚举的顺序无关,即我用(a,b)(c,d)还是(c,d)(a,b)都是一种结果,那么我们不妨每次都让最小的先加进来。这样复杂度降为$O(20 * n^{20})$

    代码:

    #include<set>
    #include<map>
    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include <iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 10 + 5;
    const int M = maxn * 30;
    const ull seed = 131;
    const int INF = 0x3f3f3f3f;
    const int MOD = 1e4 + 7;
    double dp[1 << 20], w[1 << 20];
    struct node{
        double x, y;
    }p[25];
    double dis(node a, node b){
        return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    int main(){
    //    for(int i = 0; i < (1 << 20); i++){
    //        for(int j = 0; j < 20; j++){
    //            if((1 << j) & i) continue;
    //            for(int k = j + 1; k < 20; k++){
    //                if((1 << k) & i) continue;
    //                nex[i].push_back((1 << j) | (1 << k));
    //            }
    //        }
    //    }
        int T, ca = 1;
        scanf("%d", &T);
        while(T--){
            double x, y;
            int n;
            scanf("%lf%lf", &x, &y);
            scanf("%d", &n);
            for(int i = 0; i < 2 * n; i++){
                scanf("%lf%lf", &p[i].x, &p[i].y);
            }
            p[2 * n].x = x, p[2 * n].y = y;
            for(int i = 0; i < 2 * n; i++){
                for(int j = i + 1; j < 2 * n; j++){
                    w[(1 << i) | (1 << j)] = min(double(INF), dis(p[i], p[j]) + dis(p[2 * n], p[i]));
                    w[(1 << i) | (1 << j)] = min(w[(1 << i) | (1 << j)], dis(p[i], p[j]) + dis(p[2 * n], p[j]));
                }
            }
            for(int i = 0; i < (1 << (2 * n)); i++) dp[i] = INF;
            dp[0] = 0;
            for(int i = 0; i < (1 << (2 * n)); i++){
                if(dp[i] == INF * 1.0) continue;
                int j;
                for(j = 0; j < 2 * n; j++){
                    if(!((1 << j) & i)) break;
                }
                for(int k = j + 1; k < 2 * n; k++){
                    if((1 << k) & i) continue;
                    dp[i | (1 << j) | (1 << k)] = min(dp[i | (1 << j) | (1 << k)], dp[i] + w[(1 << j) | (1 << k)]);
                }
            }
            printf("Case #%d: %.2f
    ", ca++, dp[(1 << (2 * n)) - 1]);
        }
        return 0;
    }
  • 相关阅读:
    日期插件,年月,年月日,时分,年月时分
    <context:annotation-config/>
    Autowired注解
    context:component-scan 注解的扫描
    Servlet 是什么 有哪些类
    spring RestTemplate 出现 NoHttpResponseException 和 ConnectionTimeoutException
    java 动态加载groovy 脚本
    java 如何实现文件变动的监听
    英文文档地址
    Resource ResourceLoader
  • 原文地址:https://www.cnblogs.com/KirinSB/p/11007027.html
Copyright © 2020-2023  润新知