POJ1753

来源:互联网 发布:mac给文件夹系统权限 编辑:程序博客网 时间:2024/06/04 18:33
------------------------
/*方法一:先算出所有状态对应的步数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);        }    }}


0 0
原创粉丝点击