类孔明棋 c语言实验,深度优先搜索中的重叠子结果的优化问题

前几天帮朋友写一个类孔明棋的算法,
上题      
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
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值