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]
View Code
  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

原文地址:https://www.cnblogs.com/LyonLys/p/USACO_checker_Lyon.html