POJ 1069 The Bermuda Triangle
Posted in PKU OJ on 五月 18th, 2010 by 纳米 – Be the first to comment2010-05-18,阅读题目,Code,WA,AC
某年GDKOI也出过这一题,所以去年写过一次这题,然后有一个点TLE的。今天重写,没有TLE了。
解题报告:
首先要做的,就是对各个三角形进行编号,方便程序设计。这个爱怎么写就怎么写。然后主过程就是硬搜了,主要优化如下:
1. 如果小三角形边长不能组成大三角形(六边形的1/6,下同),则直接输出NO
2. 如果同种小三角形能直接组成大三角形,则直接输出YES
3. 当前剩余的面积无法用小三角形组合而成,剪枝
4. 搜小三角形的时候,从大到小搜
5. 先搜1/6,然后搜1/3、1/2,再搜索整个大三角形。为什么呢?如果用小三角形能组成1/6的六边形,则整个六边形都显然可以用小三角形组合而成,1/3、1/2同理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | #include <stdio.h> #include <stdlib.h> #include <string.h> const int maxn = 53, maxm = 11, maxcb = 3755; int n, m, nw, data[maxm], pow[maxn], pw[maxn][2]; bool cf[maxn][maxn], cb[maxcb]; int input() { scanf("%d%d", &n, &m); for (int i = 1; i <= m; ++i) scanf("%d", &data[i]); return 0; } int comp(int *x, int *y) { return *y - *x; } int work_init() { for (int i = 0; i <= n; ++i) pow[i] = i * i; qsort(&data[1], m, sizeof(int), (int(*) (const void*, const void*)) comp); int m0 = 0, pt = pow[n] * 6; data[0] = 0; for (int i = 1; i <= m; ++i) if (data[i] <= n && data[i] != data[i-1]) data[++m0] = data[i]; m = m0; memset(cb, 0, sizeof(cb)); cb[0] = 1; for (int i = 1; i <= m; ++i) for (int j = pow[data[i]], jj = 0; j <= pt; ++j, ++jj) cb[j] = cb[jj] || cb[j]; nw = n & 1; return 0; } bool check_line() { bool dp[maxn]; memset(dp, 0, sizeof(dp)); dp[0] = 1; for (int i = 1; i <= m; ++i) for (int j = data[i]; j <= n; ++j) dp[j] = dp[j-data[i]] || dp[j]; return dp[n]; } bool can_fill(int x, int y, int t) { if (((x + y) & 1) == nw) { x += t-1, y += t-1; for (int i = 0; i < t; ++i) for (int j = -i; j <= i; ++j) if (!cf[x-i][y+j]) return false; } else { for (int i = 0; i < t; ++i) for (int j = -i; j <= i; ++j) if (!cf[x+i][y+j]) return false; } return true; } void fill(int x, int y, int t, bool w) { if (((x + y) & 1) == nw) { for (int i = 0; i < t; ++i) for (int j = -i; j <= i; ++j) cf[x+t-i-1][y+t+j-1] = w; } else { for (int i = 0; i < t; ++i) for (int j = -i; j <= i; ++j) cf[x+i][y+j] = w; } } bool search(int x, int y, int s) { bool res = false; int x0 = y < pw[x][1] ? x : x + 1; int y0 = y < pw[x][1] ? y + 1 : pw[x+1][0]; if (!s) { res = true; } else if (cf[x][y]) { for (int i = 1; i <= m && !res; ++i) if (can_fill(x, y, data[i]) && cb[s - pow[data[i]]]) { fill(x, y, data[i], 0); res = search(x0, y0, s - pow[data[i]]); fill(x, y, data[i], 1); } } else { res = search(x0, y0, s); } return res; } bool check_1() { memset(cf, 0, sizeof(cf)); pw[0][0] = n + 1; pw[0][1] = n - 1; for (int i = 1; i <= n; ++i) { pw[i][0] = pw[i-1][0] - 1; pw[i][1] = pw[i-1][1] + 1; for (int j = pw[i][0]; j <= pw[i][1]; ++j) cf[i][j] = 1; } return search(1, n, pow[n]); } bool check_2() { memset(cf, 0, sizeof(cf)); pw[0][0] = n + 1; pw[0][1] = n + n + n; for (int i = 1; i <= n; ++i) { pw[i][0] = pw[i-1][0] - 1; pw[i][1] = pw[i-1][1] - 1; for (int j = pw[i][0]; j <= pw[i][1]; ++j) cf[i][j] = 1; } return search(1, n, pow[n] * 2); } bool check_3() { memset(cf, 0, sizeof(cf)); pw[0][0] = n + 1; pw[0][1] = n + n + n - 1; for (int i = 1; i <= n; ++i) { pw[i][0] = pw[i-1][0] - 1; pw[i][1] = pw[i-1][1] + 1; for (int j = pw[i][0]; j <= pw[i][1]; ++j) cf[i][j] = 1; } return search(1, n, pow[n] * 3); } bool check_6() { memset(cf, 0, sizeof(cf)); pw[0][0] = n + 1; pw[0][1] = n + n + n - 1; for (int i = 1; i <= n + n; ++i) { if (i != n+1) { pw[i][0] = i <= n ? pw[i-1][0] - 1 : pw[i-1][0] + 1; pw[i][1] = i <= n ? pw[i-1][1] + 1 : pw[i-1][1] - 1; } else { pw[i][0] = pw[i-1][0]; pw[i][1] = pw[i-1][1]; } for (int j = pw[i][0]; j <= pw[i][1]; ++j) cf[i][j] = 1; } return search(1, n, pow[n] * 6); } bool work_check() { for (int i = 1; i <= m; ++i) if (n % data[i] == 0) return true; if (!check_line()) return false; if (check_1() || check_2() || check_3() || check_6()) return true; return false; } int main() { int testCases; scanf("%d", &testCases); while (testCases--) { input(); work_init(); if (work_check()) printf("YES\n"); else printf("NO\n"); } return 0; } |