前几天帮朋友写一个类孔明棋的算法,
上题
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