pku2965 The Pilots Brothers' refrigerator

 

第一道双向广搜,188MS

题意:给定一个4X4的“+”“-”图,定义操作[i,j]为改变第i行和第j列的状态,输出使原图变为全“-”图的最小的操作数和各具体操作

#include  < iostream >
using   namespace  std;

#define  MAXN 2<<17

int  r[ 5 ] = { 0 , 61440 , 3840 , 240 , 15 };
int  c[ 5 ] = { 0 , 34952 , 17476 , 8738 , 4369 };
int  rc[ 5 ][ 5 ] = {
    {
0 , 0 , 0 , 0 , 0 },
    {
0 , 32768 , 16384 , 8192 , 4096 },
    {
0 , 2048 , 1024 , 512 , 256 },
    {
0 , 128 , 64 , 32 , 16 },
    {
0 , 8 , 4 , 2 , 1 }
};

int  open[MAXN],head,tail,mk[MAXN],st,ed,opera[MAXN],pre[MAXN],ans[MAXN],cnt;

char  ss[ 6 ][ 6 ];

int  change( int  i, int  j, int  s){
    
int  ns;
    
    ns
=~ (r[i] ^ ( ~ s));
    ns
=~ (c[j] ^ ( ~ ns));
    ns
=~ (rc[i][j] ^ ( ~ ns));

    
return  ns;
}

void  output( int  s, int  ns){
    
if (mk[s] == 2 ){
        
int  t = s;
        s
= ns;
        ns
= t;
    }
    
while (s != st){
        ans[cnt
++ ] = opera[s];
        s
= pre[s];
    };

    
while (ns != ed){
        ans[cnt
++ ] = opera[ns];
        ns
= pre[ns];
    };
}



void  solve(){
    
int  i,j,s,ns;
    
if (st == ed){
        printf(
" 0\n " );
        
return ;
    }
    open[
0 ] = st;
    open[
1 ] = ed;
    mk[st]
= 1 ;
    mk[ed]
= 2 ;
    head
= 0 ;
    tail
= 2 ;
    
while (head < tail){

        s
= open[head ++ ];
        
for (i = 1 ;i <= 4 ;i ++ ){
            
for (j = 1 ;j <= 4 ;j ++ ){
                ns
= change(i,j,s);
                
if ( ! mk[ns]){
                    mk[ns]
= mk[s];
                    opera[ns]
= i * 10 + j;
                    pre[ns]
= s;
                    open[tail
++ ] = ns;
                }
                
else {
                    
if (mk[s] != mk[ns]){
                        
// cout<<"!!\n";
                        
// printf("%d %d\n",i,j);
                        ans[cnt ++ ] = i * 10 + j;
                        output(s,ns);
                        
return ;
                    }
                }
            }
        }
    }
    
return ;
}



int  main(){
    cnt
= 0 ;
    
int  i,j,k;
    
for (i = 0 ;i < 4 ;i ++ )
        gets(ss[i]);

    st
= ed = 0 ;
    k
= 0 ;

    
// 建立st的位图
     for (i = 3 ;i >= 0 ;i -- ){
        
for (j = 3 ;j >= 0 ;j -- ){
            
if (ss[i][j] == ' + ' )
                st
+= 1 << k;
            k
++ ;
        }
    }

    solve();
    printf(
" %d\n " ,cnt);
    
for (i = 0 ;i < cnt;i ++ )
        printf(
" %d %d\n " ,ans[i] / 10 ,ans[i] % 10 );

    
return   0 ;
}
    

你可能感兴趣的:(pku)