USACO checker 暨 华工赛后总结
今天去华工赛被虐得是那个体无完肤,整个队伍5小时内开了4题,但是只出了2题。居然比我们学校的女队还差。因为昨晚的这道USACO的checker搞到我今天下午毫无精神,到了赛场就只想趴下睡觉。最终,在我开了一题看似可以做的字符串匹配题,经过我的深思熟虑,发现不能简单完成后,我就累趴了一个小时。
赛后,我们学校的大神告诉我,那题要RMQ和LCA什么的,听的我一头雾水,突然觉得离他们又遥远许多。比赛的时候,两个队友状态很一般,最大的水题(模拟扫雷标数)居然一个说不会扫雷,一个说不想看,最后搞到我睡醒后怒秒了那题!然后他们俩继续卡他们的暴搜题。A题暴搜题,在队友赛后的解释后,我终于明白那水的无语的原理,后悔当初比赛过程中没有问清他们,而且那时他们是理解错题意的……= =最最糟的是,我睡醒之后看了一下那题,指出他们看错题意了,但是他们却用一个依照我说的题意写的一个错误代码反驳我说是我理解错了。赛后我问大神题目的意思后,狠狠地批了他一顿!
整个比赛他们卡了两题,一题应该是细节问题,另一题则是不会用树状数组优化而导致超时。而我则是算法未精,除了那弱智的模拟题,一题都没出。于是,回到宿舍就继续我的USACO training。
回到USACO,这道checker实际上是一道皇后(queens)问题,主要用到的算法是dfs剪枝。这题的规模相对较大,最多要算到13阶的矩阵。在看题目给出的hint前,我就已经接触过皇后问题的简单剪枝方法,于是我一气呵成的打出经过列储存优化后的dfs代码。可是,这题比较麻烦,直接行列优化的dfs最多只能1.11s完成13阶的求解,而题目要求1 computer second内完成这个case,于是我就从昨晚开始,带着这0.1s差距去打华工赛。
这题如果只是简单的优化肯定是不行的。因此,hint里面提到了利用解的对称性来减少计算的次数。这也是我第一次遇到必须经过对称优化才能过的题目。
棋子排列的解是存在旋转对称的关系,所以理论上最多可以优化到只计算1/4的解。可是,我想了很久,只能想到1/2的优化,不过对于我这个只差0.1s就ac的代码,我的要求并不需要太高。USACO也有提及过,比赛的时候,不是看你的代码比别人快多少,而是看你代码通过的时间比别人早多少。所以,在计算过复杂度后,如果算法不算慢,就不应该纠结于是否还有得优化。当然,在平时的训练中,别人有更快的方法的话,我们是必须学习一下的。
好了,给出我优化后的代码吧!
这是运行的结果:(最大数据是13)
Test 1: TEST OK [0.000 secs, 3344 KB] Test 2: TEST OK [0.000 secs, 3344 KB] Test 3: TEST OK [0.000 secs, 3344 KB] Test 4: TEST OK [0.000 secs, 3344 KB] Test 5: TEST OK [0.000 secs, 3344 KB] Test 6: TEST OK [0.011 secs, 3344 KB] Test 7: TEST OK [0.097 secs, 3344 KB] Test 8: TEST OK [0.572 secs, 3344 KB]
1 /* 2 ID: lyon.ly1 3 LANG: C++ 4 TASK: checker 5 */ 6 7 #include "cstdio" 8 #include "cstdlib" 9 #include "cstring" 10 #include "cmath" 11 #include "cctype" 12 #include "vector" 13 #include "set" 14 #include "map" 15 #include "string" 16 #include "algorithm" 17 #include "stack" 18 #include "queue" 19 20 #define INF 0x7fffffff 21 #define reset(a) memset(a, 0, sizeof(a)) 22 #define copy(a, b) memcpy(a, b, sizeof(b)) 23 #define PI acos(-1) 24 #define FMAX (1E300) 25 #define MAX 1000000000 26 #define eps 1E-6 27 #define feq(a, b) (fabs((a)-(b))<1E-6) 28 #define flq(a, b) ((a)<(b)||feq(a, b)) 29 #define MAXN 10005 30 #define BASE 137 31 #define PASS puts("pass") 32 #define max2(a, b) ((a) > (b)? (a) : (b)) 33 #define min2(a, b) ((a) < (b)? (a) : (b)) 34 35 36 #define ONLINE 1 37 #define USACO 0 38 #if ONLINE 39 #if USACO 40 #define FILEIN(f) fin=fopen(f, "r") 41 #define FILEOUT(f) fout=fopen(f, "w") 42 #define scanf(...) fscanf(fin, __VA_ARGS__) 43 #define printf(...) fprintf(fout, __VA_ARGS__) 44 #define getchar() fgetc(fin) 45 #define putchar(a) fputc(a, fout) 46 #define gets(a) fgets(a, 80, fin) 47 #define puts(a) fputs(a, fout) 48 FILE *fin, *fout; 49 #else 50 #define FILEIN(f) freopen("test.in", "r", stdin) 51 #define FILEOUT(f) freopen("test.out", "w", stdout) 52 #endif 53 #endif 54 55 using namespace std; 56 bool row[15]; 57 int num; 58 int list[3][15], cur[15]; 59 bool mp[15][15]; 60 61 void print(int size){ 62 printf("pattern\n"); 63 for (int i = 1; i <= size; i++){ 64 for (int j = 1; j <= size; j++) 65 printf("%d ", mp[i][j]); 66 puts(""); 67 } 68 } 69 70 bool check(int size, int x, int y){ 71 if (x + y >= size){ 72 for (int i = x + y - size; i <= size; i++) 73 if (mp[x + y - i][i]) 74 return false; 75 } 76 else{ 77 for (int i = 1; i <= x + y - 1; i++) 78 if (mp[x + y - i][i]) 79 return false; 80 } 81 82 if (x >= y){ 83 for (int i = x - y + 1; i <= size; i++) 84 if (mp[i][i + y - x]) 85 return false; 86 } 87 else{ 88 for (int i = y - x + 1; i <= size; i++) 89 if (mp[i + x - y][i]) 90 return false; 91 } 92 93 return true; 94 } 95 96 void dfs(int pos, int aim){ 97 /**/ 98 if (pos > aim){ 99 //print(aim); 100 if (num < 3){ 101 memcpy(list[num], cur, sizeof(cur)); 102 } 103 num++; 104 } 105 /**/ 106 int tmp = aim; 107 if (pos == 1){ 108 if (aim & 1) 109 tmp = aim / 2 + 1; 110 else 111 tmp = aim / 2; 112 //printf("tmp = %d\n", tmp); 113 } 114 else if ((cur[pos - 1] == (aim / 2 + 1)) && pos == 2 && (aim & 1)){ 115 tmp = aim / 2; 116 //printf("tmp = %d\n", tmp); 117 } 118 for (int i = 1; i <= tmp; i++){ 119 //print(aim); 120 //printf("result of pos %d %d: %d\n", pos, i, check(aim, pos, i)); 121 if (!row[i] && !mp[pos - 1][i - 1] && !mp[pos - 1][i + 1] && check(aim, pos, i)){ 122 cur[pos] = i; 123 mp[pos][i] = true; 124 row[i] = true; 125 /** 126 if (pos == aim){ 127 //print(aim); 128 if (num < 3) 129 memcpy(list[num], cur, sizeof(cur)); 130 num++; 131 row[i] = false; 132 mp[pos][i] = false; 133 break; 134 } 135 else 136 /**/ 137 dfs(pos + 1, aim); 138 row[i] = false; 139 mp[pos][i] = false; 140 } 141 } 142 } 143 144 int main(){ 145 FILEIN("checker.in"); 146 FILEOUT("checker.out"); 147 148 int n; 149 150 while (~scanf("%d", &n)){ 151 reset(row); 152 reset(mp); 153 reset(list); 154 reset(cur); 155 num = 0; 156 dfs(1, n); 157 if (num <= 2){ 158 int i = num - 1, j = num; 159 while (i >= 0 && j < 3){ 160 if (n & 1){ 161 list[j][1] = list[i][1]; 162 for (int k = 2; k <= n; k++) 163 list[j][k] = n + 1 - list[i][k]; 164 } 165 else{ 166 for (int k = 1; k <= n; k++) 167 list[j][k] = n + 1 - list[i][k]; 168 } 169 i--; 170 j++; 171 } 172 } 173 num *= 2; 174 for (int i = 0; i < num && i < 3; i++){ 175 for (int j = 1; j < n; j++){ 176 printf("%d ", list[i][j]); 177 } 178 printf("%d\n", list[i][n]); 179 } 180 printf("%d\n", num); 181 } 182 183 return 0; 184 }
written by Lyon