POJ1753

------------------------
/*
方法一:先算出所有状态对应的步数
POJ1753
首先需要明确:
1.棋盘最多只能走16步,2^16=65536因此可以枚举来解题(其实每格棋子最

多只可以翻转一次(实际是奇数次,但这没意义),只要其中一格重复翻了

2次(不论是连续翻动还是不连翻动),那么它以及周边的棋子和没翻动时的

状态是一致的,由此就可以确定这个棋盘最多只能走16步)
2.
每种状态可以转化为一个数,然后每次改变只要做对应的位操作。
4*4的b,w可以看作16为0,1组成的数字。

思路:
3.step[x],x表示输入棋盘状态所对应的数字,step[x]表示步数

4.0,65535是最终的状态,逆推求出只需要走一步的棋盘状态所对应的数:
分别翻动第1~16位,tmp数组记录下这16个数,step[xi]=1,step

[xi^65535]=1;别忘了全为b或者全为w都可以,如果x翻动一次就可以了,那

x^65535也只要翻动1次就可以了。

5.求出只需要走2步的棋盘状态所对应的数:
在走1步的基础上再走1步,相当于相互异或(思考下为什么是异或~)

6.求表示三步状态的数:把1步的跟2步的数异或,就是相当于在走了2步的

基础上再走一步。(需要防止重复)

7..以此类推,算出直至表示16步状态的数,改变step数组以他们为下标的

值

会发现有些数字转化为0,65535是需要一样的步数
383,2287,4919,7128,29262,36046,58407,,,



*/


#include<cstdio>
const int N=66536;
bool  vist[N];
int step[N],tmp[N];
int top=0;
void Init_step1()
{
    int i,cur,cur_t;
    for(i=0;i<16;++i){
        cur=cur_t=1<<i;
        if(i%4!=0) cur|=cur_t>>1;
        if((i+1)%4!=0) cur|=cur_t<<1;
        if(i-4>=0)cur|=cur_t>>4;
        if(i+4<16)cur|=cur_t<<4;
        if(!vist[cur]){
            vist[cur]=true,vist[cur^65535]=true;
            tmp[top++]=cur;
            step[cur]=1,step[cur^65535]=1;
           // printf("----%d   %d\      n",cur,cur^65535);
        }
    }
    vist[0]=vist[65535]=true;
}
void Init_step2_16()
{
    int stepp,ptr1,ptr2,pre,pre_top,cur;
    for(stepp=2,pre=0,pre_top=16;stepp<17;++stepp){
        for(ptr2=pre;ptr2<pre_top;++ptr2){
            for(ptr1=0;ptr1<16;++ptr1){
                cur=tmp[ptr2]^tmp[ptr1];
                if(!vist[cur]){
                    vist[cur]=true;vist[cur^65535]=true;
                    tmp[top++]=cur;
                    step[cur]=stepp;
                    step[cur^65535]=stepp;
                }
            }
        }
        pre=pre_top;
        pre_top=top;
        printf("pre=%d pre_top=%d stepp=%d\n",pre,pre_top,stepp);
    }
}
int main()
{
    char str[5][5];
    Init_step1();
    Init_step2_16();
   // printf("saass%d\n",step[38441]);
    int i,j,x,cnt;
    while(~scanf("%s",str[0])){
        for(i=1;i<4;++i)
            scanf("%s",str[i]);
        for(i=0,cnt=15,x=0;i<4;++i)
            for(j=0;j<4;++j,--cnt)if(str[i][j]=='b')x|=1<<cnt;
        if(x==0||x==65535)
            printf("0\n");
        else if(!step[x])
            puts("Impossible");
        else
            printf("%d\n",step[x]);
    }
}

-----------------------------


-------------------------------

/*
方法2:考虑所有可能,暴力求解。分别翻动1~16位,翻动次数从1到16若还没有解,则为不可能
*/


#include<cstdio>
#include<cstring>
const int N=66536;
bool  vist[N];
int step[N],tmp[N];
int top=1;
int change(int i,int cur)
{
        int cur_t;
        cur_t=1<<i;cur^=cur_t;
        if(i%4!=0) cur^=cur_t>>1;
        if((i+1)%4!=0) cur^=cur_t<<1;
        if(i-4>=0)cur^=cur_t>>4;
        if(i+4<16)cur^=cur_t<<4;
        return cur;
}
int calc_ans(int x)
{
    int i,cur,pre,stepp,ptr1,st,ed;
    tmp[0]=x;
    vist[x]=true;
    for(stepp=1,st=0,ed=1;stepp<17;++stepp){
        for(ptr1=st;ptr1<ed;++ptr1){
            pre=tmp[ptr1];
            for(i=0;i<16;++i){
                cur=change(i,pre);
                if(cur==0||cur==65535)return stepp;
                if(!vist[cur]){
                    vist[cur]=true;
                    tmp[top++]=cur;
                }
            }
        }
        st=ed;ed=top;
    }
    return -1;
}
int main()
{
    char str[5][5];
    int i,j,x,cnt,ans=-1;
    while(~scanf("%s",str[0])){
        memset(vist,0,sizeof(vist));
        top=1;
        for(ans=-1,i=1;i<4;++i)
            scanf("%s",str[i]);
        for(i=0,cnt=15,x=0;i<4;++i)
            for(j=0;j<4;++j,--cnt)if(str[i][j]=='b')x|=1<<cnt;
        if(x==0||x==65535)
            printf("0\n");
        else{
            ans=calc_ans(x);
            if(ans<0)
                puts("Impossible");
            else
                printf("%d\n",ans);
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值