您的位置:首页 > 其它

成长轨迹56 【ACM算法之路 百炼poj.grids.cn】【简单枚举】【2811:熄灯问题】

2012-02-25 11:20 239 查看
虽然ac了,但后面对自己的代码有些疑问。。。

题目http://poj.grids.cn/practice/2811

//1、将数组开大一些,使用公式时就可以不用考虑边界
//2、熄灯规则:这一层灯亮,则下一层的对应按键按下
//3、无论开关多少次,将其开次数相加,mod2就可以知道其当前状态
//这样处理,第一行的按键并不会改变
//4、遍历第一层所有按键的情况,因为只有开和关,可以利用二进制+1方式遍历
//模拟二进制,每次加1处理以遍历000000~111111

【wa代码】

#include <stdio.h>
#include <string.h>
int state[6][8],press[6][8];//1、将数组开大一些,使用公式时就可以不用考虑边界

bool deal()
{
for(int j=1;j<6;j++)
for(int k=1;k<7;k++)//2、熄灯规则:这一层灯亮,则下一层的对应按键按下
press[j+1][k]=(state[j][k]+press[j][k]+press[j-1][k]+press[j][k-1]+press[j][k+1])%2;
//3、无论开关多少次,将其开次数相加,mod2就可以知道其当前状态
//这样处理,第一行的按键并不会改变

for(int k=1;k<7;k++)
if((state[5][k]+press[5][k]+press[4][k]+press[5][k-1]+press[5][k+1])%2)
return false;

return true;
}

int main()
{
int t;
scanf("%d",&t);
for(int i=0;i<t;i++)
{
for(int j=0;j<8;j++)
state[0][j]=0;
for(int j=0;j<6;j++)
{
state[j][0]=state[j][7]=0;
memset(press[j],0,sizeof(press[j]));
}

for(int j=1;j<6;j++)
for(int k=1;k<7;k++)
scanf("%d",&state[j][k]);

int c=1;
while(press[1][c]<=1)//这里c是这次处理中被修改的最后一位
//4、遍历第一层所有按键的情况,因为只有开和关,可以利用二进制+1方式遍历
//模拟二进制,每次加1处理以遍历000000~111111
{
c=1;
press[1][c]++;
while(press[1][c]>1)
{
if(c==6)
break;
press[1][c]=0;
c++;
press[1][c]++;
}

if(deal())
{
printf("PUZZLE #%d\n",i+1);
for(int j=1;j<6;j++)
{
printf("%d",press[j][1]);
for(int k=2;k<7;k++)
printf(" %d",press[j][k]);
printf("\n");

}
break;//【这里不跳出还会继续查的。。。】
}
}
}
return 0;
}


【ac标程】

View Code

//看下标程。。后面还有我刚刚那个的改正版
#include<stdio.h>
int press[6][8];
int puzzle[6][8];
bool guess(){
int i,j;
for(i=2;i<=5;i++){
for(j=1;j<=6;j++){
press[i][j]=(press[i-1][j]+puzzle[i-1][j]+press[i-1][j-1]+press[i-2][j]+press[i-1][j+1])%2;
}
}
for(j=1;j<=6;j++){
if(press[5][j]!=(puzzle[5][j]+press[5][j-1]+press[5][j+1]+press[4][j])%2)
return false;
}
return true;
}
void process(){
int c;
for(c=1;c<=6;c++)
press[1][c]=0;
while(!guess()){
press[1][1]++;
c=1;
while(press[1][c]>1){
press[1][c]=0;
c++;
press[1][c]++;
}
}
}
int main(){
int t,i,n,j;
for(i=0;i<8;i++)
press[0][i]=puzzle[0][i]=0;
for(i=1;i<6;i++)
press[i][0]=puzzle[i][0]=press[i][7]=puzzle[i][7]=0;
scanf("%d",&t);
for(n=1;n<=t;n++){
for(i=1;i<=5;i++)
for(j=1;j<=6;j++)
scanf("%d",&puzzle[i][j]);
process();
printf("PUZZLE #%d\n",n);
for(i=1;i<=5;i++){
for(j=1;j<=6;j++){
printf("%d ",press[i][j]);
}
printf("\n");
}
}
return 0;
}


分析附后
【我的ac代码】

//发现press[1][c]<=1这个判断条件可能有错
#include <stdio.h>
#include <string.h>
int state[6][8],press[6][8];//1、将数组开大一些,使用公式时就可以不用考虑边界
int i;
bool deal()
{
for(int j=1;j<6;j++)
for(int k=1;k<7;k++)//2、熄灯规则:这一层灯亮,则下一层的对应按键按下
press[j+1][k]=(state[j][k]+press[j][k]+press[j-1][k]+press[j][k-1]+press[j][k+1])%2;
//3、无论开关多少次,将其开次数相加,mod2就可以知道其当前状态
//这样处理,第一行的按键并不会改变

for(int k=1;k<7;k++)
if((state[5][k]+press[5][k]+press[4][k]+press[5][k-1]+press[5][k+1])%2)
return false;

printf("PUZZLE #%d\n",i+1);
for(int j=1;j<6;j++)
{
printf("%d",press[j][1]);
for(int k=2;k<7;k++)
printf(" %d",press[j][k]);
printf("\n");
}
return true;
}

int main()
{
int t;
scanf("%d",&t);
for(i=0;i<t;i++)
{
for(int j=0;j<8;j++)
state[0][j]=0;
for(int j=0;j<6;j++)
{
state[j][0]=state[j][7]=0;
memset(press[j],0,sizeof(press[j]));
}

for(int j=1;j<6;j++)
for(int k=1;k<7;k++)
scanf("%d",&state[j][k]);

int c=1;
while(!deal())
//4、遍历第一层所有按键的情况,因为只有开和关,可以利用二进制+1方式遍历
//模拟二进制,每次加1处理以遍历000000~111111
{
c=1;
press[1][c]++;
while(press[1][c]>1)
{
if(c==6)
break;
press[1][c]=0;
c++;
press[1][c]++;
}

}
}
return 0;
}


【疑问】
我ac和wa的两个结构到底有什么区别呢?
【wrong】

int c=1;
while(press[1][c]<=1)//这里c是这次处理中被修改的最后一位
//4、遍历第一层所有按键的情况,因为只有开和关,可以利用二进制+1方式遍历
//模拟二进制,每次加1处理以遍历000000~111111
{
c=1;
press[1][c]++;
while(press[1][c]>1)
{
if(c==6)
break;
press[1][c]=0;
c++;
press[1][c]++;
}

if(deal())
{
printf("PUZZLE #%d\n",i+1);
for(int j=1;j<6;j++)
{
printf("%d",press[j][1]);
for(int k=2;k<7;k++)
printf(" %d",press[j][k]);
printf("\n");

}
break;//【这里不跳出还会继续查的。。。】
}
}


【right】

bool deal()
{
……
printf("PUZZLE #%d\n",i+1);
for(int j=1;j<6;j++)
{
printf("%d",press[j][1]);
for(int k=2;k<7;k++)
printf(" %d",press[j][k]);
printf("\n");

}
return true;
}
while(!deal())
//4、遍历第一层所有按键的情况,因为只有开和关,可以利用二进制+1方式遍历
//模拟二进制,每次加1处理以遍历000000~111111
{
c=1;
press[1][c]++;
while(press[1][c]>1)
{
if(c==6)
break;
press[1][c]=0;
c++;
press[1][c]++;
}

}


仔细看可以知道,
1、第一个的if(deal())里边的东西被放进了第二个的deal()的return true之前,这两个写法是等价的
2、第二个的while条件做出了修改,但是第一个的if(deal())里边也有break,所以这两个也等价

两个的区别就是第一个有条件press[1][c]<=1,第二个没有。同时两个都有deal()如果成功就跳出的条件

 但是这个c是修改的最后一位啊,它跳出的条件只能是最后一位是2.。。既然这样错了,意思是第一个(带有条件press[1][c]<=1)可能在deal()成功之前跳出(因为成功之后就跳出了,就算那个条件在成功之后不满足那也无所谓。所以,只能是在成功之前跳出导致出错),那么就是说。。press[1][c]在>1时还不应跳出,因为deal()还没有成功,再等一下就成功了。。。但是从000000遍历到111111还不成功是什么情况?!

唔。。。求高人解答了。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐