08年区域赛北京赛区 http://poj.org/searchproblem?field=source&key=Beijing+2008
POJ 3921 Destroying the bus stations
题目还是比较难的,当时的榜似乎只有4/25的通过/提交,其实题目数据很水。学长转换模型写了网络流求最小割,可以AC,不过自己造了个数据推翻了正确性。我写了个很挫的bfs套bfs,外层是最小的删除点数,内层是求最短路,数据很水可以AC。但比较蛋疼的在于bfs耗内存,而且队列中的点数是阶乘的复杂度,面对学长的数据直接跪了。
正解是迭代加深搜索,逐步加大删除的点数,然后bfs求最短路。虽然面对强数据还是弱,但是是我已知的最优解了。
额,好像漏了个关键的地方了。我们要删的点肯定是当前最短路上的点,所以依次枚举最短路上的点删除,如果都不行,就删除新图中的最短路上的点,这就是一个递归的过程。
代码比较挫就不贴了。
POJ 3922 A simple stone game
很厉害的博弈,k倍动态减法。还没研究。。
POJ 3923 Ugly Windows
就是个小模拟。开始忘记了一个小框完全覆盖大框的情况。然后还有一种容易忽略的情况是,被遮住只剩下一行。我是判断能不能从一个点出发再走回到自己,然后遍历左上到右下,没有其他框的代表字母即可。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstdlib> 7 #include<set> 8 #include<map> 9 #include<queue> 10 #include<ctime> 11 #include<string> 12 using namespace std; 13 14 struct point{ 15 int r, c; 16 } st[100]; 17 bool vis[300][300]; 18 int anssize, n, m; 19 int ct[100]; 20 char str[300][300], ans[100]; 21 int dr[] = {1, -1, 0, 0}, 22 dc[] = {0, 0, 1, -1}; 23 int lx[30], 24 ly[30]; 25 bool check(int id) 26 { 27 int cnt = 0; 28 int rr = st[id].r, cc = st[id].c; 29 int start = rr, end = cc; 30 bool flag = false; 31 while(cnt < ct[id]){ 32 //printf("%d %d %d\n", rr, cc, cnt); 33 vis[rr][cc] = true; 34 cnt ++; 35 int i, nr, nc; 36 for (i = 0; i < 4; i++){ 37 nr = rr + dr[i], 38 nc = cc + dc[i]; 39 if (nr > n-1 || nc > m-1 || nr < 0 || nc < 0) 40 continue; 41 if (cnt == ct[id] && nr == start && nc == end) flag = true; 42 if (vis[nr][nc] || str[nr][nc] - ‘A‘ != id) continue; 43 break; 44 } 45 if (i == 4) break; 46 else{ 47 rr = nr; 48 cc = nc; 49 } 50 } 51 bool flag2 = true; 52 char tmp = id + ‘A‘; 53 for (int i = lx[id]; i <= start; i++){ 54 if (!flag2) break; 55 for (int j = ly[id]; j <= end; j++) 56 if (str[i][j] != ‘.‘ && str[i][j] != tmp){ 57 flag2 = false; 58 break; 59 } 60 } 61 if (cnt == ct[id] && flag && flag2) return true; 62 else return false; 63 } 64 int main() 65 { 66 while(scanf("%d %d", &n, &m) && (n+m)) 67 { 68 memset(st, 0, sizeof(st)); 69 memset(vis, false, sizeof(vis)); 70 memset(ct, 0, sizeof(ct)); 71 for (int i = 0; i < n; i++){ 72 scanf("%s", str[i]); 73 for (int j = 0; j < m; j++){ 74 if (str[i][j] != ‘.‘){ 75 ct[str[i][j]-‘A‘] ++; 76 if (ct[str[i][j]-‘A‘] == 1){ 77 lx[str[i][j]-‘A‘] = i; 78 ly[str[i][j]-‘A‘] = j; 79 } 80 st[str[i][j]-‘A‘].r = i; 81 st[str[i][j]-‘A‘].c = j; 82 } 83 } 84 } 85 anssize = 0; 86 for (int i = 0; i < 26; i++) 87 if (ct[i]){ 88 if (check(i)){ 89 ans[anssize++] = i + ‘A‘; 90 } 91 } 92 ans[anssize] = ‘\0‘; 93 printf("%s\n", ans); 94 } 95 return 0; 96 }
POJ 3924 Tornado
貌似是最难的一道,计算几何,还没做。
POJ 3925 Minimal Ratio Tree
乍一看很厉害,其实点数很少,直接枚举所选的点,然后就是求最小生成树了。开始读错题,以为答案是升序排列,字典序最大的,多了很多无用代码和一个WA。。然后读入没读好,后面懒得改就写了手很生的prim。。代码挺挫。。
1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 const double eps = 1e-6; 8 int n, m; 9 bool vis[20]; 10 int a[20], d[20]; 11 bool use[20]; 12 double bestratio; 13 int edgesum, pointsum; 14 int e[20][20]; 15 int tmpans[20], ans[20]; 16 void dfs(int dep, int pos) 17 { 18 if (dep == m){ 19 int cnt = 0; 20 pointsum = 0; 21 for (int i = 1; i <= n; i++) 22 if (use[i]){ 23 cnt++; 24 pointsum += a[i]; 25 } 26 if (cnt < m) return; 27 memset(d, 127, sizeof(d)); 28 memset(vis, false, sizeof(vis)); 29 int nx, mi = d[0] + 1; 30 edgesum = 0; 31 for (int j = 0; j <= m-1; j++){ 32 mi = d[0] + 1; 33 for (int i = 1; i <= n; i++){ 34 if (use[i] && !vis[i] && d[i] < mi){ 35 nx = i; 36 mi = d[i]; 37 } 38 } 39 vis[nx] = true; 40 if (d[nx] != d[0]) edgesum += d[nx]; 41 for (int i = 1; i <= n; i++){ 42 if (use[i] && d[i] > e[nx][i]){ 43 d[i] = e[nx][i]; 44 } 45 } 46 } 47 double tmp = double(edgesum)/double(pointsum); 48 if (tmp < bestratio){ 49 bestratio = tmp; 50 int p = 1; 51 for (int i = 0; i < m; i++){ 52 while(!use[p]) p++; 53 ans[i] = p; 54 p++; 55 } 56 } 57 else if (fabs(tmp - bestratio) < eps){ 58 int p = 1; 59 for (int i = 0; i < m; i++){ 60 while(!use[p]) p++; 61 tmpans[i] = p; 62 p++; 63 } 64 int i; 65 for (i = 0; i < m; i++){ 66 if (tmpans[i] > ans[i]) return; 67 if (tmpans[i] < ans[i]) break; 68 } 69 if (i != m){ 70 for (int j = 0; j < m; j++) 71 ans[j] = tmpans[j]; 72 bestratio = tmp; 73 } 74 } 75 return; 76 } 77 for (int i = pos+1; i <= n; i++) 78 if (!use[i]){ 79 use[i] = true; 80 dfs(dep+1, i); 81 use[i] = false; 82 } 83 } 84 int main() 85 { 86 while(scanf("%d %d", &n, &m) && n + m) 87 { 88 for (int i = 1; i <= n; i++) 89 scanf("%d", a+i); 90 int x, y, z; 91 for (int i = 1; i <= n; i++) 92 for (int j = 1; j <= n; j++){ 93 scanf("%d", &z); 94 e[i][j] = z; 95 } 96 bestratio = 1e10; 97 memset(use, false, sizeof(use)); 98 dfs(0, 0); 99 for (int i = 0; i < m-1; i++) 100 printf("%d ", ans[i]); 101 printf("%d\n", ans[m-1]); 102 } 103 return 0; 104 }
POJ 3926 Parade
按行转移,很容易就可以推出转移方程,然后需要单调队列优化复杂度,目前还没写。
POJ 3927 Priest John‘s Busiest Day
贪心的思路还是很明确的,因为牧师祝福的时间要超过长度的一半,所以中间的位置是必须要经过的,我们就按这个来排序,从头开始,尽量把祝福时间往前放,留给后面更多空间,如果这样还不能保证中间位置不重叠,那就是NO了。
但是具体的边界细节我想得不是很清楚,本来想乘以2就可以规避左右一奇一偶的情况,但是后来又想不清楚了。。反正也AC了。。不想管了。。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 7 struct node{ 8 long long l, r; 9 } a[100100]; 10 bool cmp(node a, node b) 11 { 12 return a.r + a.l <= b.r + b.l; 13 } 14 int n; 15 int main() 16 { 17 while(scanf("%d", &n) && n) 18 { 19 for (int i = 0; i < n; i++){ 20 scanf("%lld%lld", &a[i].l, &a[i].r); 21 a[i].l *= 2ll; 22 a[i].r *= 2ll; 23 } 24 sort(a, a + n, cmp); 25 bool flag = true; 26 long long pre = 0; 27 for (int i = 0; i < n; i++){ 28 long long tmp = (a[i].l + a[i].r)/2ll; 29 if (pre >= tmp){ 30 flag = false; 31 break; 32 } 33 pre = 1ll + max(pre, a[i].l) + (a[i].r - a[i].l)/2ll; 34 } 35 if (flag) 36 puts("YES"); 37 else 38 puts("NO"); 39 } 40 return 0; 41 }
POJ 3928 Ping pong
主要就是一个统计的过程,需要一个查找比较快的数据结构,树状数组就可以胜任。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 5 const int maxn = 100000; 6 int T; 7 int bef[20010], aft[20010], a[20010], equ[20010][2]; 8 int pre[maxn+100], nex[maxn+100]; 9 long long ans; 10 int n; 11 int lowbit(int x) 12 { 13 return x & -x; 14 } 15 void update(int x, int val, int sum[]) 16 { 17 for (int i = x; i <= maxn; i += lowbit(i)) 18 sum[i] += val; 19 } 20 int query(int x, int sum[]) 21 { 22 int ans = 0; 23 for (int i = x; i > 0; i -= lowbit(i)) 24 ans += sum[i]; 25 return ans; 26 } 27 int main() 28 { 29 scanf("%d", &T); 30 while(T--) 31 { 32 memset(pre, 0, sizeof(pre)); 33 memset(nex, 0, sizeof(nex)); 34 scanf("%d", &n); 35 for (int i = 1; i <= n; i++){ 36 scanf("%d", &a[i]); 37 bef[i] = query(a[i], pre); 38 equ[i][0] = bef[i] - query(a[i]-1, pre); 39 update(a[i], 1, pre); 40 } 41 for (int i = n; i >= 1; i--){ 42 aft[i] = query(a[i], nex); 43 equ[i][1] = aft[i] - query(a[i]-1, nex); 44 update(a[i], 1, nex); 45 } 46 ans = 0; 47 for (int i = 1; i <= n; i++){ 48 ans += (long long) bef[i] * (n-i-aft[i]) + (long long) (i-1-bef[i]) * aft[i]; 49 ans += (long long) equ[i][0] * equ[i][1]; 50 } 51 printf("%lld\n", ans); 52 } 53 return 0; 54 }
POJ 3929 Timer
virtual赛的时候还推了半天。。微积分水平还是比较拙计的。。现在还没做出来。。
POJ 3930 Elevator
很大一只模拟。。目测是不会去写了。。
08年acm区域赛北京赛区 部分题解题报告,布布扣,bubuko.com