HDU 3920【状态压缩DP +优化】

题意:

有2n个敌人,给出你的坐标和敌人的坐标,让你射n次枪将所有敌人杀死,每一次可以且仅可以射死两个敌人。

解题思路:

刚开始无任何证明地用了最小生成树提交,wa,然后状态压缩DP,TLE,看了解题报告才知道自己的状态压缩DP写得有点萎,原来可以从O(2^n*(n*n))优化O(n2^n),以前从未想过。

View Code
 1 #include <iostream>
2 #include <cstdio>
3 #include <string>
4 #include <cstring>
5 #include <algorithm>
6 #include <vector>
7 #include <cmath>
8 #include <map>
9
10 #define DX(x) ((x)*(x))
11 using namespace std;
12
13 const int MAX = 20 + 1;
14 const double INF = 1e10;
15
16 struct TCoord
17 {
18 double x, y;
19 }Coord[MAX];
20 TCoord st;
21 double D[MAX][MAX];
22 double DP[1 << MAX];
23
24 inline double getDist(const TCoord& a, const TCoord& b)
25 {
26 return sqrt(DX(a.x - b.x) + DX(a.y - b.y));
27 }
28
29 inline double getMin(double a, double b)
30 {
31 return a < b ? a : b;
32 }
33
34 void init(int n)
35 {
36 int e = 1 << n;
37 for(int i = 0; i < e; ++i)
38 DP[i] = INF;
39 }
40
41 int main()
42 {
43 freopen("in.txt", "r", stdin);
44 int T;
45 int n;
46 scanf("%d", &T);
47 for(int t = 1; t <= T; ++t)
48 {
49 scanf("%lf%lf", &st.x, &st.y);
50 scanf("%d", &n);
51 n = n << 1;
52 init(n);
53 for(int i = 0; i < n; ++i)
54 {
55 scanf("%lf%lf", &Coord[i].x, &Coord[i].y);
56 D[i][i] = getDist(Coord[i], st);
57 }
58 for(int i = 0; i < n; ++i)
59 {
60 for(int j = i + 1; j < n; ++j)
61 {
62 D[i][j] = D[j][i] = getDist(Coord[i], Coord[j]);
63 }
64 }
65 DP[0] = 0;
66 int end = 1 << n;
67 double d = INF;
68 int tg;
69 for(int s = 0, i, j; s < end; ++s)
70 {
71 if(DP[s] == INF)
72 continue;
73 for(i = 0; i < n; ++i) //优化1,选第一个点
74 {
75 if((s & (1 << i)) == 0)
76 break;
77 }
78 for(j = i + 1; j < n; ++j) /优化2,选后面的点与上面组合,这样不会失去子集最优解,减少了重复运算。
79 {
80 if((s & (1 << j)) == 0)
81 {
82 d = getMin(D[i][i], D[j][j]) + D[i][j];
83 tg = s | (1 << i) | (1 << j);
84 if(DP[tg] > DP[s] + d)
85 DP[tg] = DP[s] + d;
86 }
87 }
88 }
89 printf("Case #%d: %.2lf\n", t, DP[end - 1]);
90 }
91 return 0;
92 }



你可能感兴趣的:(HDU)