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

HDU 3920   Clear All of Them I

题目是说有2n个敌人,现在可以发n枚炮弹,每枚炮弹可以(可以且仅可以)打两个敌人,每一枚炮弹的花费等于它所行进的距离,现在要消灭所有的敌人,问最少花费是多少(反正题意大概就是这样啦,知道怎么回事就好了,解释不清了)

一看到n<=10而且又是在DP专题里的,就知道这个显然是状压DP,由于有2n个敌人,所以状态表示由当前状态再打两个人来转移,

10000100表示打了这两个敌人的最小花费

所以状态的转移是由前往后递推的,假如当前状态是cur,上一个状态是last,应该满足存在i!=j有last&(1<<i)=0且last&(1<<j)=0且last | (1<<i)|(1<<j) = cur,由此来更新当前的状态cur,最后的答案就是DP[(1<<(2n)) - 1]

注意到上面我们是要枚举i和j的,所以这个的总复杂度就是20 * 20 * 2^20,这显然是会超时的, 所以需要优化

注意到如果存在两队人(a,b)(c,d)我们先打(a, b)再打(c, d)和先打(c,d)在打(a, b)是一样的,所以我们完全可以每次取last中最小的一位是0的与后面所有的0组合,这样不仅没有漏掉解,而且复杂度也将到了O(20 * 2^20)这就可以过了

下面从前往后美剧上一个状态时递推时我是用的队列存的所有状态,其实枚举过去也是可以的

  1 //#pragma comment(linker,"/STACK:102400000,102400000")
  2 #include <map>
  3 #include <set>
  4 #include <stack>
  5 #include <queue>
  6 #include <cmath>
  7 #include <ctime>
  8 #include <vector>
  9 #include <cstdio>
 10 #include <cctype>
 11 #include <cstring>
 12 #include <cstdlib>
 13 #include <iostream>
 14 #include <algorithm>
 15 using namespace std;
 16 #define INF 1e9
 17 #define inf (-((LL)1<<40))
 18 #define lson k<<1, L, mid
 19 #define rson k<<1|1, mid+1, R
 20 #define mem0(a) memset(a,0,sizeof(a))
 21 #define mem1(a) memset(a,-1,sizeof(a))
 22 #define mem(a, b) memset(a, b, sizeof(a))
 23 #define FOPENIN(IN) freopen(IN, "r", stdin)
 24 #define FOPENOUT(OUT) freopen(OUT, "w", stdout)
 25 template<class T> T CMP_MIN(T a, T b) { return a < b; }
 26 template<class T> T CMP_MAX(T a, T b) { return a > b; }
 27 template<class T> T MAX(T a, T b) { return a > b ? a : b; }
 28 template<class T> T MIN(T a, T b) { return a < b ? a : b; }
 29 template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
 30 template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b;    }
 31
 32 //typedef __int64 LL;
 33 //typedef long long LL;
 34 const int MAXN = 105;
 35 const int MAXM = 100005;
 36 const double eps = 1e-13;
 37 //const LL MOD = 1000000007;
 38
 39 int T, N;
 40 typedef double Point[2];
 41 Point st, p[MAXN];
 42 double dis[MAXN][MAXN], d[MAXN], dp[1<<21];
 43
 44 double calc(Point a, Point b)
 45 {
 46     double x = a[0] - b[0];
 47     double y = a[1] - b[1];
 48     return sqrt(x*x + y*y);
 49 }
 50
 51 void getDis()
 52 {
 53     for(int i=0;i<N;i++)
 54     {
 55         d[i] = calc(st, p[i]);
 56         for(int j=i+1;j<N;j++)
 57         {
 58             dis[j][i] = dis[i][j] = calc(p[i], p[j]);
 59         }
 60     }
 61 }
 62
 63 int main()
 64 {
 65     int t = 0;
 66     scanf("%d", &T);
 67     while(T--)
 68     {
 69         scanf("%lf %lf", &st[0], &st[1]);
 70         scanf("%d", &N);
 71         N <<= 1;
 72         for(int i=0;i<N;i++)
 73             scanf("%lf %lf", &p[i][0], &p[i][1]);
 74         getDis();
 75         dp[0] = 0;
 76         for(int i=1;i<(1<<N);i++) dp[i] = INF;
 77         queue<int>q;
 78         q.push(0);
 79         while(!q.empty())
 80         {
 81             int now = q.front(); q.pop();
 82             int f=0, r;
 83             while( now & (1<<f)  && f < N)
 84                 f++;
 85             for(r = f + 1; r < N; r ++ )
 86                 if(!(now & (1<<r)))
 87             {
 88                 int next = now | (1<<f) | (1<<r);
 89                 double minDis = MIN(d[f], d[r]) + dis[f][r];
 90                 if( fabs(dp[next] - INF) < eps )
 91                 {
 92                     q.push(next);
 93                     dp[next] = dp[now] + minDis;
 94                 }
 95                 else if( dp[now] + minDis < dp[next] )
 96                     dp[next] = dp[now] + minDis;
 97             }
 98         }
 99         printf("Case #%d: %.2lf%\n", ++t, dp[(1<<N)-1]);
100     }
101     return 0;
102 }

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

时间: 2024-10-10 17:27:39

HDU 3920Clear All of Them I(状压DP)的相关文章

HDU 4856 Tunnels (最短路+状压DP)

题意:给你N*N的网格,'.'表示可以走,'#'表示不能走,m条管道,每条管道有起点和终点坐标, Bob每次可以走到相邻的网格花费1s,问Bob走完m条管道要花多少时间:Bob在管道内不计算时间 即计算Bob从管道 i 的出口走到管道 j 的入口的时间Dis(e[i],s[j])的最小和,起点可以任意: 思路:看了题解说是状态压缩DP然后深入理解了下. 首先算出d[e[i]][s[j]]的最短距离,不能到达为-1: dp[i][j] : 表示以 j 为起点状态为 i 的最小值.其中 i 是用十进

HDU 1074:Doing Homework(状压DP)

http://acm.hdu.edu.cn/showproblem.php?pid=1074 Doing Homework Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 7704    Accepted Submission(s): 3484 Problem Description Ignatius has just come bac

HDU 5067 Harry And Dig Machine(状压DP)(TSP问题)

题目地址:pid=5067">HDU 5067 经典的TSP旅行商问题模型. 状压DP. 先分别预处理出来每两个石子堆的距离.然后将题目转化成10个城市每一个城市至少经过一次的最短时间模型.然后简单的状压DP就可以. 代码例如以下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #incl

HDU 6149 Valley Numer II(状压DP)

题目链接 HDU6149 百度之星复赛的题目……比赛的时候并没有做出来. 由于低点只有15个,所以我们可以考虑状压DP. 利用01背包的思想,依次考虑每个低点,然后枚举每个状态. 在每个状态里面任意枚举不在这个状态中的两个点,如果能构成一个valley,那么更新答案. #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i,

hdu 2167 方格取数 【状压dp】(经典)

<题目链接> 题目大意: 给出一些数字组成的n*n阶矩阵,这些数字都在[10,99]内,并且这个矩阵的  3<=n<=15,从这个矩阵中随机取出一些数字,在取完某个数字后,该数字周围8个点都不能取,问:取得数字的最大和为多少? 解题分析: 由于对每一个数,有选和不选两种可能,分别对应状态压缩中的1和0,且 n<=15,1<<15不是非常大,因此就可以非常自然的想到状态压缩. 此题要与普通的状压dp不同的是,当某一行取某种方案时,如何求出这种取数的所有取得的数之和,

HDU 1565 方格取数(1)(状压dp)

感觉这道题目的数据比较水啊,程序的时间复杂度为1711^2*20竟然也可以过掉....其他的就是状压了啊,注意需要滚动一下啊.... 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5701    Accepted Submission(s): 2159 Problem Description 给你一个n*n的格子的棋

HDU 5067 Harry And Dig Machine(状压dp)

感觉这两天怎么老是遇到状压啊.... 数字20以下,首想状压啊... 不过这题犯抽忘记考虑没有石头的时候了啊. 简单的状压:表示状态为j时以第i的作为结束. PS:这题也在表扬大蓝翔的挖掘机技术啊.醉了啊... Harry And Dig Machine Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 468    Accepted S

hdu 2825 Wireless Password(AC自动机+状压DP)

题目链接:hdu 2825 Wireless Password 题目大意:N,M,K,M个字符串作为关键码集合,现在要求长度为N,包含K个以上的关键码的字符串有多少个. 解题思路:AC自动机+dp,滚动数组,因为关键码个数不会超过10个,所以我们用二进制数表示匹配的状态.dp[i][j][k] 表示到第i个位置,j节点,匹配k个字符串. #include <cstdio> #include <cstring> #include <queue> #include <

HDU 3001 Travelling 3进制状压dp

题意:10个点,若干条边,边有花费,每个点最多走两次,求走过所有点,花费最少 分析:因为每个点最多走两次,所以联想到3进制,然后枚举状态,就行了(我也是照着网上大神的代码写的) #include <cstdio> #include <iostream> #include <cstring> #include <cstdlib> #include <vector> #include <string> #include <cmath