【洛谷 P2346】四子连棋(状态压缩,搜索)

其实这题可以直接二进制状压做,1表示黑棋,0表示白棋,另外记录下2个空点的位置就行了。
具体看代码(冗长):

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define rep(i,m,n) for(int i=m;i<=n;++i)
#define dop(i,m,n) for(int i=m;i>=n;--i)
#define lowbit(x) (x&(-x))
#define ll long long
#define INF 2147483647
#define re register
#define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define Close fclose(stdin);fclose(stdout);
#define pause system("pause");
using namespace std;
inline int read(){
    int s = 0, w = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-')w = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0',ch = getchar();
    return s * w;
}
char a[6][6];
struct Node{
    int x[2], y[2], s, time, who; //x,y数组记录2个空点的位置,s表示当前的状态(二进制),who表示到谁走了
}start, begin, now, tmp;
int getHash(){  //棋盘转二进制状态
    int ans = 0;
    rep(i, 1, 4) rep(j, 1, 4) if(a[i][j] == 'B') ans |= (1 << ( ((i - 1) << 2) + j - 1) );
    return ans;
}
queue  q;
bool Win(Node x){ //判赢函数
    int s = x.s;
    //判断有没有黑点四子连棋
    if( s&1&&s&(1<<4)&&s&(1<<8)&&s&(1<<12) || s&(1<<1)&&s&(1<<5)&&s&(1<<9)&&s&(1<<13) 
    || s&(1<<2)&&s&(1<<6)&&s&(1<<10)&&s&(1<<14) || s&(1<<3)&&s&(1<<7)&&s&(1<<11)&&s&(1<<15)
    || s&1&&s&(1<<1)&&s&(1<<2)&&s&(1<<3) || s&(1<<4)&&s&(1<<5)&&s&(1<<6)&&s&(1<<7)
    || s&(1<<8)&&s&(1<<9)&&s&(1<<10)&&s&(1<<11) || s&(1<<12)&&s&(1<<13)&&s&(1<<14)&&s&(1<<15)
    || s&1&&s&(1<<5)&&s&(1<<10)&&s&(1<<15) || s&(1<<3)&&s&(1<<6)&&s&(1<<9)&&s&(1<<12))
      return true;
    //把空点的位置赋值为1
    s|=1<<(((x.x[0]-1)<<2)+x.y[0]-1); s|=1<<(((x.x[1]-1)<<2)+x.y[1]-1);
    //rep(i, 1, 4){ rep(j, 1, 4) printf("%d ", (s>>(((i-1)<<2)+j-1))&1); printf("\n"); }
    //判断白点有没有四子连棋
    if( (s^1)&1&&(s^(1<<4))&(1<<4)&&(s^(1<<8))&(1<<8)&&(s^(1<<12))&(1<<12) || (s^(1<<1))&(1<<1)&&(s^(1<<5))&(1<<5)&&(s^(1<<9))&(1<<9)&&(s^(1<<13))&(1<<13) 
    || (s^(1<<2))&(1<<2)&&(s^(1<<6))&(1<<6)&&(s^(1<<10))&(1<<10)&&(s^(1<<14))&(1<<14) || (s^(1<<3))&(1<<3)&&(s^(1<<7))&(1<<7)&&(s^(1<<11))&(1<<11)&&(s^(1<<15))&(1<<15)
    || (s^1)&&(s^(1<<1))&(1<<1)&&(s^(1<<2))&(1<<2)&&(s^(1<<3))&(1<<3) || (s^(1<<4))&(1<<4)&&(s^(1<<5))&(1<<5)&&(s^(1<<6))&(1<<6)&&(s^(1<<7))&(1<<7)
    || (s^(1<<8))&(1<<8)&&(s^(1<<9))&(1<<9)&&(s^(1<<10))&(1<<10)&&(s^(1<<11))&(1<<11) || (s^(1<<12))&(1<<12)&&(s^(1<<13))&(1<<13)&&(s^(1<<14))&(1<<14)&&(s^(1<<15))&(1<<15)
    || (s^1)&(1)&&(s^(1<<5))&(1<<5)&&(s^(1<<10))&(1<<10)&&(s^(1<<15))&(1<<15) || (s^(1<<3))&(1<<3)&&(s^(1<<6))&(1<<6)&&(s^(1<<9))&(1<<9)&&(s^(1<<12))&(1<<12))
      return true;
    return false;
}
int l[] = { 233, -1, 1, 0, 0 }, r[] = { 666, 0, 0, -1, 1 }, id, X, Y, kong, v[20000010];
int getHash(Node x){   //不要hack我
    return x.s + x.x[0] * 10007 + x.x[1] * 107 + x.y[1] * 677 + x.y[0] * 97;
}
int main(){
    rep(i, 1, 4)
       rep(j, 1, 4){
          cin>>a[i][j];
          if(a[i][j] == 'O') //记录空点位置
            if(!start.x[0]) start.x[0] = i, start.y[0] = j;
            else start.x[1] = i, start.y[1] = j;
       }
    start.s = getHash();
    start.time = 0;
    begin = start;
    start.who = 0;
    begin.who = 1;
    q.push(start);
    q.push(begin);
    v[getHash(begin)] = v[getHash(start)] = 1;
    while(!q.empty()){  //bfs
      Node now = q.front();
      q.pop();
      rep(i, 0, 1){
         rep(j, 1, 4){
            X = now.x[i] + l[j]; Y = now.y[i] + r[j];
            if(X <= 0 || X > 4 || Y <= 0 || Y > 4 || X == now.x[i^1] && Y == now.y[i^1]) continue; //不能出界,也不能走到另外一个空点
            id = ((X - 1) << 2) + Y - 1;
            kong = ((now.x[i] - 1) << 2) + now.y[i] - 1;
            if(((now.s >> id) & 1) == now.who){ //如果是到这个棋走
              tmp = now;
              tmp.s &= ~(1 << id);      //交换
              tmp.s |= tmp.who << kong; //位置
              tmp.x[i] = X;
              tmp.y[i] = Y;
              if(v[getHash(tmp)]) continue;
              v[getHash(tmp)] = 1;
              tmp.time++;
              tmp.who^=1;
              if(Win(tmp)){ 
                printf("%d\n", tmp.time); 
                return 0; 
              }
              q.push(tmp);
            }
         }
      }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Qihoo360/p/9468315.html

你可能感兴趣的:(【洛谷 P2346】四子连棋(状态压缩,搜索))