前几天帮朋友写一个类孔明棋的算法,
上题
5*5的棋盘 .表示没棋子 o表示有棋子
如: ooooo
ooooo
oo.oo
ooooo
ooooo
走法和孔明的走法一样
开始直接就是一个深搜 没有用数据结构 用的数组
#include<stdio.h> #include <iostream> #include <string.h> using namespace std; char data[5][5]; //棋盘 int tag; //记录棋盘上有多少个棋子 int n=0; //记录方案个数 int scheme [25][4]; int code; //记录数据 int path(int z){ //递归还原数据 加输出数据 if(z==0){ //递归结束的条件 for(int i=0;i<5;i++){ for(int j=0;j<5;j++) printf("%c",data[i][j]); printf("\n"); } printf("\n"); } else{ data[(scheme[z][0]+scheme[z][2])/2][(scheme[z][1]+scheme[z][3])/2]='o'; data[scheme[z][0]][scheme[z][1]]='o'; data[scheme[z][2]][scheme[z][3]]='.'; path(z-1); //递归 上面是还原数据 下面是移动棋子 data[(scheme[z][0]+scheme[z][2])/2][(scheme[z][1]+scheme[z][3])/2]='.'; data[scheme[z][0]][scheme[z][1]]='.'; data[scheme[z][2]][scheme[z][3]]='o'; for(int i=0;i<5;i++){ for(int j=0;j<5;j++) printf("%c",data[i][j]); printf("\n"); } printf("\n"); } } int dfs(int x,int y,int z){ //深搜 if(tag==1) { n++; //记录可行个数 path(z-1); // 初步输出棋盘 /* //方法输出 printf("方案为:"); for(int i=0;i<z;i++) printf("%d.%d->%d.%d ",scheme[i][0],scheme[i][1],scheme[i][2],scheme[i][3]); printf("\n"); */ return 1; } for(int i=0;i<5;i++){ for(int j=0;j<5;j++){ if(data[i][j]=='o') { //双重循环加判断找出棋子的位置 x=i; y=j; //判断各个方向是否可以走 if(x>=2&&data[x-1][y]=='o'&&data[x-2][y]=='.'){ //上 data[x][y]='.'; data[x-1][y]='.'; data[x-2][y]='o'; scheme[z][0]=x; scheme[z][1]=y; scheme[z][2]=x-2; scheme[z][3]=y; tag--; code=dfs(0,0,z+1); //上面的是移动位置 记录位置 减少棋子数 if(code==1) return 1; //递归到下一层 data[x][y]='o'; //下面的是恢复位置 增加棋子数 data[x-1][y]='o'; data[x-2][y]='.'; tag++; } if(x<=2&&data[x+1][y]=='o'&&data[x+2][y]=='.'){ //下 data[x][y]='.'; data[x+1][y]='.'; data[x+2][y]='o'; scheme[z][0]=x; scheme[z][1]=y; scheme[z][2]=x+2; scheme[z][3]=y; tag--; code=dfs(0,0,z+1); if(code==1) return 1; data[x][y]='o'; data[x+1][y]='o'; data[x+2][y]='.'; tag++; } if(y>=2&&data[x][y-1]=='o'&&data[x][y-2]=='.'){ //左 data[x][y]='.'; data[x][y-1]='.'; data[x][y-2]='o'; scheme[z][0]=x; scheme[z][1]=y; scheme[z][2]=x; scheme[z][3]=y-2; tag--; if(dfs(0,0,z+1)==1) return 1; data[x][y]='o'; data[x][y-1]='o'; data[x][y-2]='.'; tag++; } if(y<=2&&data[x][y+1]=='o'&&data[x][y+2]=='.'){ //右 data[x][y]='.'; data[x][y+1]='.'; data[x][y+2]='o'; scheme[z][0]=x; scheme[z][1]=y; scheme[z][2]=x; scheme[z][3]=y+2; tag--; code=dfs(0,0,z+1); if(code==1) return 1; data[x][y]='o'; data[x][y+1]='o'; data[x][y+2]='.'; tag++; } } } } return 0; } int main(){ int k=0; for(int i=0;i<5;i++){ for(int j=0;j<5;j++){ cin>>data[i][j]; } } //输入 for(int i=0;i<5;i++){ for(int j=0;j<5;j++){ if(data[i][j]=='o') k++; } //记录初始棋子个数 } tag=k; printf("\n"); dfs(0,0,0); //深搜 if(n==0) printf("无解\n"); return 0; }
然后问题就来了 2个小时没跑出结果 简单的深度优先搜索简单的说就是穷举,所以需要减枝
后来 准备用空间换时间,加上一个标记,去掉重叠子问题
bool record[32][32][32][32][32]; //标记这用来记录不可行的子问题
后来的修正版
#include<stdio.h> #include <iostream> #include <time.h> #include <string.h> using namespace std; char data[6][6]; //棋盘 int tag; //记录棋盘上有多少个棋子 int n=0; //记录方案个数 int scheme [25][4]; int code; //记录数据 bool record[32][32][32][32][32]; //标记 int sum[5]; void path(int z){ //递归还原数据 加输出数据 if(z==0){ //递归结束的条件 for(int i=0;i<5;i++){ for(int j=0;j<5;j++) printf("%c",data[i][j]); printf("\n"); } printf("\n"); } else{ data[(scheme[z][0]+scheme[z][2])/2][(scheme[z][1]+scheme[z][3])/2]='o'; data[scheme[z][0]][scheme[z][1]]='o'; data[scheme[z][2]][scheme[z][3]]='.'; path(z-1); //递归 上面是还原数据 下面是移动棋子 data[(scheme[z][0]+scheme[z][2])/2][(scheme[z][1]+scheme[z][3])/2]='.'; data[scheme[z][0]][scheme[z][1]]='.'; data[scheme[z][2]][scheme[z][3]]='o'; for(int i=0;i<5;i++){ for(int j=0;j<5;j++) printf("%c",data[i][j]); printf("\n"); } printf("\n"); } } int dfs(int x,int y,int z){ //深搜 if(tag==1) { for(int i=0;i<5;i++) for(int j=0;j<5;j++){ if(data[i][j]==0) data[i][j]='.'; else data[i][j]='o'; } n++; path(z-1); /* printf("方案为:"); for(int i=0;i<z;i++) printf("%d.%d->%d.%d ",scheme[i][0],scheme[i][1],scheme[i][2],scheme[i][3]); printf("\n"); */ return 1; } for(int i=0;i<5;i++) sum[i]=data[i][0]*16+data[i][1]*8+data[i][2]*4+data[i][3]*2+data[i][4]; if(record [sum[0]][sum[1]][sum[2]][sum[3]][sum[4]]==false) return 0; for(int i=0;i<5;i++){ for(int j=0;j<5;j++){ if(data[i][j]==1) { //双重循环加判断找出棋子的位置 x=i; y=j; //判断各个方向是否可以走 if(x>=2&&data[x-1][y]==1&&data[x-2][y]==0){ //上 data[x][y]=0; data[x-1][y]=0; data[x-2][y]=1; scheme[z][0]=x; scheme[z][1]=y; scheme[z][2]=x-2; scheme[z][3]=y; tag--; code=dfs(0,0,z+1); //上面的是移动位置 记录位置 减少棋子数 if(code==1) return 1; //递归到下一层 data[x][y]=1; //下面的是恢复位置 增加棋子数 data[x-1][y]=1; data[x-2][y]=0; tag++; } if(x<=2&&data[x+1][y]==1&&data[x+2][y]==0){ //下 data[x][y]=0; data[x+1][y]=0; data[x+2][y]=1; scheme[z][0]=x; scheme[z][1]=y; scheme[z][2]=x+2; scheme[z][3]=y; tag--; code=dfs(0,0,z+1); if(code==1) return 1; data[x][y]=1; data[x+1][y]=1; data[x+2][y]=0; tag++; } if(y>=2&&data[x][y-1]==1&&data[x][y-2]==0){ //左 data[x][y]=0; data[x][y-1]=0; data[x][y-2]=1; scheme[z][0]=x; scheme[z][1]=y; scheme[z][2]=x; scheme[z][3]=y-2; tag--; if(dfs(0,0,z+1)==1) return 1; data[x][y]=1; data[x][y-1]=1; data[x][y-2]=0; tag++; } if(y<=2&&data[x][y+1]==1&&data[x][y+2]==0){ //右 data[x][y]=0; data[x][y+1]=0; data[x][y+2]=1; scheme[z][0]=x; scheme[z][1]=y; scheme[z][2]=x; scheme[z][3]=y+2; tag--; code=dfs(0,0,z+1); if(code==1) return 1; data[x][y]=1; data[x][y+1]=1; data[x][y+2]=0; tag++; } } } } for(int i=0;i<5;i++) sum[i]=data[i][0]*16+data[i][1]*8+data[i][2]*4+data[i][3]*2+data[i][4]; record[sum[0]][sum[1]][sum[2]][sum[3]][sum[4]]=false; return 0; } int main(){ int k=0; for(int i=0;i<5;i++){ for(int j=0;j<5;j++) cin>>data[i][j]; } //输入 for(int i=0;i<5;i++){ for(int j=0;j<5;j++){ if(data[i][j]=='o') { k++; data[i][j]=49-'0'; } else { data[i][j]=49-'1'; } } //记录初始棋子个数 } for(int i1=0;i1<32;i1++) //记录初始棋子个数 for(int i2=0;i2<32;i2++) for(int i3=0;i3<32;i3++) for(int i4=0;i4<32;i4++) for(int i5=0;i5<32;i5++){ record[i1][i2][i3][i4][i5]=true; } tag=k; printf("\n"); dfs(0,0,0); //深搜 if(n==0) printf("无解\n"); return 0; }
修正版的运行时间在1S以内
另外附上一个我看到的别人大佬写的类孔明棋算法
https://blog.csdn.net/tmljs1988/article/details/6039101