回 帖 发 新 帖 刷新版面

主题:第32次编程比赛第二题结果

这次比赛终于让我看到了牛人iAkiak的风采,的确非常的牛啊.
比赛结果倒是次要的了,我学到了不少东西啊.
     先说测试结果,
     1  iAkiak测试通过,速度非常的快,和其他人相比.
     2 boxterny   对某些数据输入没有结果,所以判为wrong answer.
     3 goal00001111 正确,不过后面几组数据出结果太慢了,没有耐心等,后面改进的几个速度还是不怎么行.
     4 yxs001 运行几组数据直接崩溃了,我用的是vc6
     6 superstar 前面16运行速度都还快,但是后面速度慢了.19比较快,可能是因为19的第一行数据小.
     


     由于这个直接凭感觉就能感觉出快慢,所以也没有定量的测时间,sorry.

      现在简要说一下iAkiak的程序.程序的主要思想是压缩状态,用一个数表示一行的状态,并且直接进行数据运算得到下一行的状态了.
如下用a,b,c表示三行
a
b
c
而下一行这样计算的.
        X
       XXX
        X
所以c = !(a^b^(b<<1)^(b>>1)),递推,最后一行再多一行全为0.
不怎么详细,大致这个思想.

我最先想到通过随机的方式产生第一行的,但是貌似大家都没有这样做......


 其他的程序没有细看,大家如果发现自己的程序有什么闪光点,在这儿说出来大家一起学习.

  最后,我宣布,本次大赛冠军为iAkiak,麻烦你出下一次题目,大家鼓掌...
  参与了比赛的回贴有分

回复列表 (共7个回复)

沙发

iAkiak好厉害,佩服佩服。

楼主啊,哪些数据没有结果?我自己测试时从1~30都有结果啊。

仔细分析了一下iAkiak的代码,非常巧妙。第1行后面n-1行的数据我是一个一个计算的,而iAkiak则利用位运算一次计算一行,这样也使得最后判断是否得到解时可以直接利用b是否与mask相等来进行。

板凳

哎呀...终于让我又出头了一次,不容易啊- -
给分给分:)
其实刚好前几天有人贴了这个问题,当时想过一些:
http://www.programfan.com/club/showbbs.asp?id=176433

3 楼

寒,竟然不太看的懂iAkiak的算法!
稍微解释一下,特别是
do
        {
            clicks[i] = c;
            b ^= c;
            b ^= (c << 1) & mask;
            b ^= (c >> 1) & mask;
            a = b;
            b = c;
            c = (a ^ mask) & mask;
        } while(++i < n - 1);
        
        clicks[i] = c;
        b ^= c;
        b ^= (c << 1) & mask;
        b ^= (c >> 1) & mask;
谢了!

4 楼

2iAkiak:

一个建议,mask 这样求比较好!这样n最大可以为32!

const ul mask = (~0u) >> (32 - n);

而原始的写法,n只能到31!不然位移32个bit,是未定义行为....

5 楼

@goal00001111, 3
其实楼主已经说出来了:)
因为每个点按下是出一个十字:
 X
XXX
 X
第一行用来填补前一行a的空白(也就是c)。
后二行是为了填补空白而留下的副作用- -
由于一行内可能点了多个地方。而他们的作用是互相叠加的。被影响奇数次的才会亮。所以是异或运算。第二行每点一个要多影响左右两个点,所以要再多异或b<<1和b>>1
连起来新的a行变为b^c^(c<<1)^(c>>1)超出部分用mask截掉。新的b行变为c。
这样一次处理一行,直到最后判断是否被填满。

@sarrow, 4
有道理!记下了:)

6 楼

终于理解了,按照自己的理解,我为iAkiak的代码写了比较罗嗦的注释,大家看看对不对.
/*
算法介绍:
1。利用一个具有32位的unsigned long型变量来存储某行灯的”暗亮“和”是否操作“信息,用这个变量的各个位值(取0或1)表示该行的每一盏灯----因此每行灯的数量不能超过32,否则出错。
2。根据初始条件(每盏灯开始都是暗的)和操作规则(可以改变其本身和周围的灯的状态),我们可以知道,当第i(1<=i<n)行的灯的”暗亮“状态确定后,第i+1行灯的”是否操作“信息就确定了,执行指令为c = (a ^ mask) & mask;其中a表示第i行的灯的”暗亮“状态,c表示第i+1行灯的”是否操作“信息,mask的所有位值均为1。
例如当n=8时,若第3行的灯的”暗亮“状态为00110101,则第四行的”是否操作“信息为11001010。
所以,我们只要确定第一行的灯的”暗亮“情况就好了,而第一行的灯的”暗亮“由它的”是否操作“信息决定,第一行的灯的”是否操作“信息有( mask = (1<<n) - 1)种可能,我们穷举分析每一种可能的情况,当出现满足条件的解时,进行输出,并停止分析;若无解则输出"NO SOLUTION".
3。那么灯的”是否操作“信息是如何来决定灯的”暗亮“情况的呢?
我们先令所有的灯开始都是暗的:b = 0
然后读入第一行灯的”是否操作“信息:c = click; clicks[i] = c;
那么某盏灯的”是否操作“信息将影响它周围的灯的”暗亮“情况:
    b ^= c;  //影响自身
    b ^= (c << 1) & mask; //影响左边的灯
    b ^= (c >> 1) & mask; //影响右边的灯
    a = b; //用临时变量a存储该行的灯的”暗亮“情况
    b = c; //影响下边的灯,用b表示下一行的灯的”暗亮“情况
    //根据该行的灯的”暗亮“情况,确定下一行灯的”是否操作“信息
    c = (a ^ mask) & mask;
    clicks[i] = c;
4。按照步骤3的方法处理1-(n-1)行,在处理最后一行时,只要执行指令
    b ^= c;  //影响自身
    b ^= (c << 1) & mask; //影响左边的灯
    b ^= (c >> 1) & mask; //影响右边的灯
    最后判断最后一行灯的”暗亮“情况,如果全亮(b == mask),则输出解。
*/

typedef unsigned long ul;

void solve(int n)
{
    const ul mask = (1<<n) - 1;
    ul clicks[20];//存储灯的”是否操作“信息,每个元素表示一行,该元素的每一位表示一盏灯
    int i, j;
    if (n == 1)
    {
        printf("1\n");
        return;
    }
    for (ul click = 0; click <= mask; click++)
    {
        ul a = 0; //临时变量,用来存储某行的灯最终的”暗亮“情况,
        ul b = 0; //用来存储某行的灯的”暗亮“情况,初始值为0
        ul c = click;//用来存储某行的灯的”是否操作“信息,第一行的初始值为 click
        i = 0;
        do  //处理1-(n-1)行
        {
            clicks[i] = c;//读入第(i+1)行灯的”是否操作“信息
            //根据第(i+1)行灯的”是否操作“信息确定该行的灯的”暗亮“情况
            b ^= c;  //影响自身
            b ^= (c << 1) & mask; //影响左边的灯
            b ^= (c >> 1) & mask; //影响右边的灯
            a = b; //用临时变量a存储该行的灯的”
            b = c; //影响下边的灯,用b表示下一行的灯的”暗亮“情况
            //根据该行的灯的”暗亮“情况,确定下一行灯的”是否操作“信息暗亮“情况
            c = (a ^ mask) & mask;
        } while(++i < n - 1);

        clicks[i] = c; //读入最末行灯的”是否操作“信息
        //确定最末行灯的”暗亮“情况
        b ^= c;
        b ^= (c << 1) & mask;
        b ^= (c >> 1) & mask;

        if (b == mask)//如果最末行灯全亮,表示有解
        {
            for (i = 0; i < n; i++)
            {
                for (j = n - 1; j > 0; j--)
                    printf("%d ", (clicks[i]>>j)&1);
                printf("%d\n", clicks[i]&1);
            }
            return;
        }
    }
    printf("NO SOLUTION\n");
}

7 楼

@goal00001111, 6
cool~ thx:)

我来回复

您尚未登录,请登录后再回复。点此登录或注册