1004 四子连棋
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 黄金 Gold
题目描述 Description
在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局。
● | ○ | ● | |
○ | ● | ○ | ● |
● | ○ | ● | ○ |
○ | ● | ○ |
输入描述 Input Description
从文件中读入一个4*4的初始棋局,黑棋子用B表示,白棋子用W表示,空格地带用O表示。
输出描述 Output Description
用最少的步数移动到目标棋局的步数。
样例输入 Sample Input
BWBO
WBWB
BWBW
WBWO
样例输出 Sample Output
5
#include<iostream> #include<cstdio> #include<cstdio> using namespace std; int map[5][5],ans,flag; int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; inline void dfs(int ch, int deep); inline void swap(int &a,int &b) { int t = a; a = b; b = t; } bool check()//判断是否符合条件 { for (int k=1;k<=4;k++) { if (map[k][1]==map[k][2]&&map[k][2]==map[k][3]&&map[k][3]==map[k][4])return 1; if (map[1][k]==map[2][k]&&map[2][k]==map[3][k]&&map[3][k]==map[4][k])return 1; } if (map[1][1]==map[2][2]&&map[2][2]==map[3][3]&&map[3][3]==map[4][4])return 1; if (map[1][4]==map[2][3]&&map[2][3]==map[3][2]&&map[3][2]==map[4][1])return 1; return 0; } void move(int ch,int deep,int x,int y) //ch表示下一个颜色 { for(int i=1;i<=4;i++) { int xx=x+dx[i],yy=y+dy[i]; if(map[xx][yy]==ch&&xx>0&&xx<5&&yy>0&&yy<5) { swap(map[x][y],map[xx][yy]); dfs(ch,deep+1); swap(map[x][y],map[xx][yy]); } } } void dfs(int ch,int deep) { int next=!ch; if(flag) return; if(ans==deep) { if(check()) flag=1; return; } for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) if(map[i][j]==-1) move(next,deep,i,j); } int main() { for(int i = 1; i <= 4; i++) for(int j = 1; j <= 4; j++) { char a; cin>>a; if(a == 'B') map[i][j] = 1; if(a == 'O') map[i][j] = -1; } for(ans = 1; flag == 0; ans++) { dfs(0, 0); if(flag) break; dfs(1, 0); if(flag) break; } printf("%d ",ans); }
#include<iostream> #include<cstdio> #include<cstring> #include<map> #define maxn 5001 using namespace std; struct node { int map[5][5]; int f;//表示这一步走的棋子是黑还是白 };node e[5000]; int mm[5][5],tep[maxn],head=0,tail=1,ans=maxn,flag; int dx[5]={0,0,0,1,-1}; int dy[5]={0,1,-1,0,0}; map<string,bool> hash; bool equ(int a1,int a2,int a3,int a4){if(a1!=a2||a2!=a3||a3!=a4||a4!=a1)return 0;return 1;} bool judge(int w) { for(int i=1;i<=4;i++) { if(equ(e[w].map[i][1],e[w].map[i][2],e[w].map[i][3],e[w].map[i][4]))return 1; if(equ(e[w].map[1][i],e[w].map[2][i],e[w].map[3][i],e[w].map[4][i]))return 1; } if(equ(e[w].map[1][1],e[w].map[2][2],e[w].map[3][3],e[w].map[4][4]))return 1; if(equ(e[w].map[1][4],e[w].map[2][3],e[w].map[3][2],e[w].map[4][1]))return 1; return 0; } void copy() { for(int k=1;k<=4;k++) for(int l=1;l<=4;l++) e[tail].map[k][l]=e[head].map[k][l]; } bool check(node x)//hash判重 { string s=""; for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) s+=x.map[i][j]+'1'; if(hash[s])return true; hash[s]=1;return false; } void Bfs() { while(head<tail) { head++; for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) { if(e[head].map[i][j]==0) { for(int cnt=1;cnt<=4;cnt++) { int x=i+dx[cnt],y=j+dy[cnt]; if(x>0&&x<5&&y>0&&y<5&&e[head].map[x][y]!=e[head].f&&e[head].map[x][y]!=0) { ++tail; copy(); e[tail].map[x][y]=0; if(e[head].f==1) { e[tail].f=-1; e[tail].map[i][j]=-1; } else { e[tail].f=1; e[tail].map[i][j]=1; } tep[tail]=tep[head]+1; if(judge(tail)) { flag=1; ans=min(ans,tep[tail]); break;//手残打成return... } if(check(e[tail])) tail--; } } } if(flag)break; } } } int main() { for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) { char c; cin>>c; if(c=='W')mm[i][j]=1; else if(c=='B')mm[i][j]=-1; else mm[i][j]=0; } for(int k=1;k<maxn;k++) for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) { e[1].map[i][j]=mm[i][j]; e[k].f=0; tep[k]=0; } flag=0;ans=maxn; e[1].f=-1; Bfs(); hash.clear(); for(int k=1;k<maxn;k++) for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) { e[1].map[i][j]=mm[i][j]; e[k].f=0; tep[k]=0; } head=0;tail=1;flag=0; e[1].f=1; Bfs();//因为一开始走黑棋白棋结果可能不一样,所以两遍 printf("%d ",ans); return 0; }