HDU3921:Clear All of Them II
——3920的加强版。这次一次设计能够反弹3个敌人。
——贪心。
——rul:http://acm.hdu.edu.cn/showproblem.php?pid=3921
————————————————————————————————————————————————————————————
题目中已经告诉我们,用贪心的方法,但是普通的贪心要n^4的复杂度,会超时。因此需要优化。
假设一次射击击中的敌人分别是A,B,C,D。
枚举B,C
找出“我”和B点到其最近的点a1和次近一个点a2,以及与C点最近的点d1及次近的一个点d2
若a1与d1不同,则用a1,B,C,d1来更新
若a1与d1相同,则用a2,B,C,d1和a1,B,C,d2来更新。
其中所有的a和d可以预先处理出来。
这样复杂度可以降低。
具体参见代码。
————————————————————————————————————
一开始我有个想法,即先预处理所有的a和d
然后枚举B,C
先找出最近的a,然后找一个不同于B,C,a的d
用a,B,C,d来更新
但是这样是错误的。
因为不能确定a2,B,C,d1和a1,B,C,d2哪个更小,而这样我默认a1,B,C,d2最小。
View Code
1 #include<stdio.h>
2 #include<math.h>
3 #include<memory.h>
4 #include<stdlib.h>
5 #define oo 0x7ffffff
6 #define eps 1e-5
7 #define N 55
8 struct node
9 {
10 double min;
11 int loc;
12 } assist1[N * 4][N*4], assist2[N*4][N*4];
13 double dis[N * 4][N*4];
14 int x[N * 4], y[N*4];
15 int bound[N * 4];
16 int xx, yy, i, j, k, l, cas, n, t, loc1, loc12, loc2, loc22, a, b,c, d;
17 double ans, min, average, tmp1, tmp2;
18 bool vis[N * 4];
19 int cmp(const void *a, const void *b)
20 {
21 return (*(node *) a).min+eps>(*(node *) b).min?1:-1;
22 }
23 double cal(int a, int b, int c, int d)
24 {
25 double x1 = (double) a, y1 = (double) b, x2 = (double) c, y2 = (double) d;
26 return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
27 }
28 void readin()
29 {
30 scanf("%d%d", &xx, &yy);
31 scanf("%d", &n);
32 for (i = 1; i <= 4 * n; i++)
33 scanf("%d%d", &x[i], &y[i]);
34 for (i = 1; i <= 4 * n; i++)
35 {
36 dis[0][i] = dis[i][0] = cal(x[i], y[i], xx, yy);
37 for (j = 1; j <= 4 * n; j++)
38 dis[i][j] = dis[j][i] = cal(x[i], y[i], x[j], y[j]);
39 }
40 for (i = 1; i <= 4 * n; i++)
41 {
42 k = -1;
43 for (j = 1; j <= 4 * n; j++)
44 if (i != j)
45 {
46 k++;
47 assist1[i][k].loc = j; //预先处理a
48 assist1[i][k].min = dis[0][j] + dis[j][i];
49 assist2[i][k].loc = j; //预先处理b
50 assist2[i][k].min = dis[j][i];
51 }
52 bound[i] = k;
53 qsort(assist1[i], k+1, sizeof(assist1[i][0]), cmp);
54 qsort(assist2[i], k+1, sizeof(assist2[i][0]), cmp);
55
56 }
57 }
58 void update(int p1, int p2, int p3, int p4)
59 {
60 tmp1 = dis[0][p1] + dis[p1][p2] + dis[p2][p3] + dis[p3][p4];
61 tmp2 = (dis[0][p1] + dis[0][p2] + dis[0][p3] + dis[0][p4]) / 4;
62 if (tmp1+eps < min || (fabs(min-tmp1)<eps && average > tmp2+eps))
63 {
64 min = tmp1;
65 average = tmp2;
66 a = p1;
67 b = p2;
68 c = p3;
69 d = p4;
70 }
71 }
72 void solve()
73 {
74 memset(vis, 0, sizeof(vis));
75 ans = 0;
76 for (i = 0; i < n; i++)
77 {
78 min = average = oo;
79 for (j = 1; j <= 4 * n; j++)
80 if (!vis[j])
81 for (k = 1; k <= 4 * n; k++)
82 if (vis[k] == false && k != j)
83 {
84 for (l = 0; l <= bound[j]; l++) //查找没有被使用的a1
85 if (vis[assist1[j][l].loc] == false
86 && assist1[j][l].loc != k)
87 break;
88 loc1 = assist1[j][l].loc;
89 for (l = l + 1; l <= bound[j]; l++) //查找没有被使用的a2
90 if (vis[assist1[j][l].loc] == false
91 && assist1[j][l].loc != k)
92 break;
93 loc12 = assist1[j][l].loc;
94 for (l = 0; l <= bound[k]; l++) //查找没有被使用的d1
95 if (vis[assist2[k][l].loc] == false
96 && assist2[k][l].loc != j)
97 break;
98 loc2 = assist2[k][l].loc;
99 for (l = l + 1; l <= bound[k]; l++) //查找没有被使用的d2
100 if (vis[assist2[k][l].loc] == false
101 && assist2[k][l].loc != j)
102 break;
103 loc22 = assist2[k][l].loc;
104 if (loc1 == loc2)
105 {
106 update(loc12, j, k, loc2);
107 update(loc1, j, k, loc22);
108 }
109 else
110 update(loc1, j, k, loc2);
111 }
112 vis[a] = vis[b] = vis[c] = vis[d] = 1;
113 ans += min;
114 }
115 printf("Case #%d: %.2lf\n", t, ans);
116 }
117 int main()
118 {
119 scanf("%d", &cas);
120 for (t = 1; t <= cas; t++)
121 {
122 readin();
123 solve();
124 }
125 return 0;
126 }