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

Posted kirinsb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n", ca++, dp[(1 << (2 * n)) - 1]);
    
    return 0;

 

以上是关于HDU 3920 Clear All of Them I(状压DP)题解的主要内容,如果未能解决你的问题,请参考以下文章

Crystal Clear Applied: The Seven Properties of Running an Agile Project (转载)

hdu 5318 The Goddess Of The Moon

HDU 1010 Tempter of the Bone

hdu 5318 The Goddess Of The Moon 矩阵高速幂

hdu 1010 Tempter of the Bone

HDU 1010 Tempter of the Bone