您的位置:首页 > 大数据 > 人工智能

USACOTrainning.Checker Challenge

2010-04-15 22:07 381 查看
这道题花了很多的时间额。。。

大意是九皇后。

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

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

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

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

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

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

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

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



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

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

AC如下:



到Chapter 2了,兴奋。

#include <iostream>
#include <string>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <time.h>
#include <queue>
#include <set>
using namespace std;

const int MAX = 15;

int n, cnt, ansCnt;
int full;    //表示都能放1111..n
int limit;    //表示优化对称用的
int stateCol[MAX];
int stateA[MAX];    //A为主对角线
int stateB[MAX];    //B为从对角线
int ans[MAX];
//表示棋盘中每行的各种方法的状态
//1表示不能放

void ready()
{
memset(stateCol, 0, sizeof(stateCol));
memset(stateA, 0, sizeof(stateA));
memset(stateB, 0, sizeof(stateB));
full = (1 << n) - 1;
limit = (1 << ((n + 1) / 2)) - 1;
cnt = 0;
ansCnt = 0;
}

int getBit(int x)
{
int res = 0;
while(x)
{
x >>= 1;
res++;
}
return res;
}

void dfs(int row, int t)
{
if(row == n)
{
cnt++;
if(cnt <= 3)
{
for(int i = 0; i < n; i++)
{
if(i == 0)  printf("%d", ans[i]);
else  printf(" %d", ans[i]);
}
printf("\n");
}
ansCnt++;
if(n > 6 && ans[0] <= n / 2)  ansCnt++;
return;
}
//先取出能放的状态,can表示能放的位置
int can = t ^ (stateCol[row] | stateA[row] | stateB[row]);
while(can)
{
int col = (can & (~can + 1));    //取最后的一位1,按顺序遍历
ans[row] = getBit(col);
stateCol[row + 1] = stateCol[row] | col;
stateA[row + 1] = ((stateA[row] | col) << 1) & full;
stateB[row + 1] = (stateB[row] | col) >> 1;
dfs(row + 1, full);
can ^= col;
}
}

void go()
{
if(n > 6)  dfs(0, limit);
else  dfs(0, full);
printf("%d\n", ansCnt);
}

int main()
{
//freopen("checker.in", "r", stdin);
//freopen("checker.out", "w", stdout);

scanf("%d", &n);
ready();
go();
}


感谢:

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

http://jingsixee.blog.hexun.com/4915336_d.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: