USACOTrainning.Checker Challenge

这道题花了很多的时间额。。。

大意是九皇后。

USACO给出的Hint很强大,但自己下还是TLE在最后一个数据上,时间消耗1.3s左右,方法就是普通的标记数组表示不能访问。

弄反斜线的坐标和索引对应时掣肘了那么几下。。。

后来看到有人说位运算,就把之前的标记数组改成了二进制状态表示,但效果一点都没有,左右是一样,代码里面还是要For那些点来判断。

就按Hint里的把多次调用的小代码放到主体中,因为大量的Call也会造成nontrial的消耗,但未果。

至于Hint里说的对称和旋转重复的部分不去跑,可以省掉不少时间,可是不会。

看了大牛们的Blog后,才知道如下:

用3个数组来表示3种情况下对应的某行的状态,然后每次都获得一个数,表示出那些位置是可以访问的,用t&(-t)的办法,可以获得最低位的1,每次的提取就省掉了没用的For了,还有用到^操作,是练习位运算的一道好题。

用了如下的位运算操作AC如下:

USACOTrainning.Checker Challenge

又有一大牛这样说,n分奇数和偶数,偶数时,第一行枚举前半段,这样求的的解一定可以在右边找到镜像。奇数时,分别枚举中间的行和列,要求都小于一般,且规定行小于列,这样可以保证旋转+镜像后的解不重复且这些解就是最终的解,只有1/8的原来的个数。

介于实现考虑,都用对称,省掉一半的时间,n=6时特判。

AC如下:

USACOTrainning.Checker Challenge

到Chapter 2了,兴奋。

  
    
1 #include < iostream >
2 #include < string >
3 #include < algorithm >
4 #include < string .h >
5 #include < vector >
6 #include < math.h >
7 #include < time.h >
8 #include < queue >
9 #include < set >
10   using namespace std;
11
12   const int MAX = 15 ;
13
14   int n, cnt, ansCnt;
15 int full; // 表示都能放1111..n
16 int limit; // 表示优化对称用的
17 int stateCol[MAX];
18 int stateA[MAX]; // A为主对角线
19 int stateB[MAX]; // B为从对角线
20 int ans[MAX];
21 // 表示棋盘中每行的各种方法的状态
22 // 1表示不能放
23
24 void ready()
25 {
26 memset(stateCol, 0 , sizeof (stateCol));
27 memset(stateA, 0 , sizeof (stateA));
28 memset(stateB, 0 , sizeof (stateB));
29 full = ( 1 << n) - 1 ;
30 limit = ( 1 << ((n + 1 ) / 2 )) - 1 ;
31 cnt = 0 ;
32 ansCnt = 0 ;
33 }
34
35 int getBit( int x)
36 {
37 int res = 0 ;
38 while (x)
39 {
40 x >>= 1 ;
41 res ++ ;
42 }
43 return res;
44 }
45
46 void dfs( int row, int t)
47 {
48 if (row == n)
49 {
50 cnt ++ ;
51 if (cnt <= 3 )
52 {
53 for ( int i = 0 ; i < n; i ++ )
54 {
55 if (i == 0 ) printf( " %d " , ans[i]);
56 else printf( " %d " , ans[i]);
57 }
58 printf( " \n " );
59 }
60 ansCnt ++ ;
61 if (n > 6 && ans[ 0 ] <= n / 2 ) ansCnt ++ ;
62 return ;
63 }
64 // 先取出能放的状态,can表示能放的位置
65 int can = t ^ (stateCol[row] | stateA[row] | stateB[row]);
66 while (can)
67 {
68 int col = (can & ( ~ can + 1 )); // 取最后的一位1,按顺序遍历
69 ans[row] = getBit(col);
70 stateCol[row + 1 ] = stateCol[row] | col;
71 stateA[row + 1 ] = ((stateA[row] | col) << 1 ) & full;
72 stateB[row + 1 ] = (stateB[row] | col) >> 1 ;
73 dfs(row + 1 , full);
74 can ^= col;
75 }
76 }
77
78 void go()
79 {
80 if (n > 6 ) dfs( 0 , limit);
81 else dfs( 0 , full);
82 printf( " %d\n " , ansCnt);
83 }
84
85 int main()
86 {
87 // freopen("checker.in", "r", stdin);
88 // freopen("checker.out", "w", stdout);
89
90 scanf( " %d " , & n);
91 ready();
92 go();
93 }

 

感谢:

http://blog.sina.com.cn/s/blog_5ed6a69f0100dywr.html

http://jingsixee.blog.hexun.com/4915336_d.html

你可能感兴趣的:(USACO)