【codevs1004】四子連棋 狀壓bfs
阿新 • • 發佈:2018-11-09
題目大意:給定一個大小為 4*4 的棋盤,分別有 7 個黑子、7 個白子和 2 個空位構成,求出至少需要移動多少步,才能使得四個相同的棋子共線。
題解:顯然每一種棋盤的局面都是一個狀態,因此需要採用狀態壓縮的搜尋。總共的局面最多有4e7種,並且所給的記憶體足夠開下雜湊表。
需要注意的是,資料中有很多不是對稱的情況,因此需要分別考慮先移動白子和黑子的情況,再取最小值,得到答案。
程式碼如下
#include <bits/stdc++.h> using namespace std; const int maxn=5e7; const int inf=0x3f3f3f3f; const int dx[]={0,0,-1,1}; const int dy[]={1,-1,0,0}; //b->1 w->0 o->2 char s[10]; int state[5][5],mp[2][maxn],ans=inf,st; bool col[maxn]; //b->1 w->0 int get_hash(int a[5][5]){ int val=0; for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) val=val*3+a[i][j]; return val; } void get_state(int val){ for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) state[i][j]=val%3,val/=3; } void read_and_parse(){ for(int i=1;i<=4;i++){ scanf("%s",s+1); for(int j=1;j<=4;j++){ if(s[j]=='B')state[i][j]=1; if(s[j]=='W')state[i][j]=0; if(s[j]=='O')state[i][j]=2; } } st=get_hash(state); } bool right(int x,int y,int cor){ if(x<1||y<1||x>4||y>4||state[x][y]!=cor)return 0; return 1; } bool check(int a[5][5]){ for(int i=1;i<=4;i++){ if(a[i][1]==a[i][2]&&a[i][2]==a[i][3]&&a[i][3]==a[i][4])return 1; if(a[1][i]==a[2][i]&&a[2][i]==a[3][i]&&a[3][i]==a[4][i])return 1; } if(a[1][1]==a[2][2]&&a[2][2]==a[3][3]&&a[3][3]==a[4][4])return 1; if(a[1][4]==a[2][3]&&a[2][3]==a[3][2]&&a[3][2]==a[4][1])return 1; return 0; } void solve(int cor){ queue<int> q; q.push(st),mp[cor][st]=1,col[st]=cor; while(q.size()){ int u=q.front();q.pop(); get_state(u); if(check(state)){ans=min(ans,mp[cor][u]-1);return;} for(int i=1;i<=4;i++)for(int j=1;j<=4;j++)if(state[i][j]==2){ for(int k=0;k<4;k++){ int nx=i+dx[k],ny=j+dy[k]; if(!right(nx,ny,col[u]))continue; swap(state[i][j],state[nx][ny]); int v=get_hash(state); if(!mp[cor][v])mp[cor][v]=mp[cor][u]+1,col[v]=col[u]^1,q.push(v); swap(state[i][j],state[nx][ny]); } } } } int main(){ read_and_parse(); solve(1);solve(0); printf("%d\n",ans); return 0; }