CSDN博客

img pipopipo

独立钻石棋(Diamond Chess)算法

发表于2004/10/9 0:43:00  2284人阅读

分类: MS阵营

第一种方法,深度搜索的递归方法
/*
CODE BY 我的BLOG AT 2004.10.13
独立钻石棋问题
深度搜索,递归调用法
*/

#include<iostream>
#include<fstream>
using namespace std;

#define IN  1       // 有棋子
#define NOTIN 0       // 没有棋子
#define NEVERIN 2       // 不可到达位置
#define MAXN 7       // 棋盘大小
#define STEP 31       // 31步结束

int c[MAXN+1][MAXN+1];      // 存储空间
int pass[4][2]={{0,-1},{-1,0},{0,1},{1,0}}; // 四个方向跳过位置
int reach[4][2]={{0,-2},{-2,0},{0,2},{2,0}};// 四个方向到达位置
bool findit = false;      // 记录是否找到结果

// 输出一个棋局
void output(int c[][MAXN+1]);
// 递归搜索解
void Search(int depth);

int main(void)
{
 ifstream cin("cin.txt");
 // 输入
 for(int i=1;i<=MAXN;i++){
  for(int j=1;j<=MAXN;j++){
   cin>>c[i][j];
  }
 }
 // 处理
 Search(0);
 // 输出
 system("pause");
 return 0;
}

void Search(int depth)
{
 if(depth == STEP && c[4][4] == 1){   // 到达目标位置
  cout<<"找到解,倒着走如下:/n";
  output(c);
  findit = true;
  return;
 }
 int x1,y1,x2,y2;
 for(int i=1;i<=MAXN;i++){
  for(int j=1;j<=MAXN;j++){
   if(c[i][j]==IN){     // 有棋子
    for(int k=0;k<4;k++){   // 4个方向   
     x1 = i+pass[k][0];
     y1 = j+pass[k][1];
     x2 = i+reach[k][0];
     y2 = j+reach[k][1];
     if(x1>=1&&x1<=MAXN&&y1>=1&&y2<=MAXN&&c[x1][y1]==IN   //跳过位置还有子
      &&x2>=1&&x2<=MAXN&&y2>=1&&y2<=MAXN&&c[x2][y2]==NOTIN){ //达到为位置为空
      c[i][j]=NOTIN;   // 初始位置置空
      c[x1][y1]=NOTIN;  // 跳过位置置空
      c[x2][y2]=IN;   // 跳到的位置置为peg
      Search(depth+1);  // 跳到目标位置
      c[i][j]=IN;    // 还原
      c[x1][y1]=IN;  
      c[x2][y2]=NOTIN; 

      if(findit == true){
       output(c);
       return;
      }
     }
    }
   }
  }
 }
}

void output(int c[][MAXN+1])
{
 cout<<"*********************************************************/n";
 for(int i=1;i<=MAXN;i++){
  for(int j=1;j<=MAXN;j++){
   cout<<c[i][j]<<" ";
  }
  cout<<"/n";
 }
}
第二种:常用方法深度搜索的open集和closed集算法,用堆是为了给启发式模板准备.
#ifndef NODE_H
#define NODE_H

#include <iostream>
using namespace std;

class Node {

 friend ostream &operator <<(ostream &output,const Node & op2);  // 输出当前布局

public:

 int c[34];         // 棋局状态
 int moveid[32];        // 各步移动的棋子号,第0个元素存放了到该棋局为止移动的步数
 int dirction[32];       // 各步的到达该局的移动方向,1,2,3,4分别为上下左右
 int key;         // 关键码,由于解空间不大,直接只用深度搜索

 Node();

 bool operator> (const Node &op2) const;  // 建堆和向量需要重载的几个运算符
 bool operator< (const Node &op2) const;
 bool operator>=(const Node &op2) const;
 bool operator==(const Node &op2) const;

 void output(ostream &out) const;   // 输出解

 bool up(int id, Node& next);    // 判断某一棋子的移动,移动后的布局存在next结点   
 bool down(int id, Node& next);
 bool left(int id, Node& next);
 bool right(int id, Node& next);

};

#endif

#include <iostream>
#include <fstream>
#include "Node.h"
using namespace std;

// 下移的位置
int downit[34][2] =
{{0,0},
{4,9},{5,10},{6,11},
{9,16},{10,17},{11,18},
{14,21},{15,22},{16,23},{17,24},{18,25},{19,26},{20,27},
{0,0},{0,0},{23,28},{24,29},{25,30},{0,0},{0,0},
{0,0},{0,0},{28,31},{29,32},{30,33},{0,0},{0,0},
{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0}};

// 上移的位置
int upit[34][2] =
{{0,0},
{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},
{0,0},{0,0},{4,1},{5,2},{6,3},{0,0},{0,0},
{0,0},{0,0},{9,4},{10,5},{11,6},{0,0},{0,0},
{14,7},{15,8},{16,9},{17,10},{18,11},{19,12},{20,13},
{23,16},{24,17},{25,18},
{28,23},{29,24},{30,25}};

// 左移的位置
int leftit[34][2] =
{{0,0},
{0,0},{0,0},{2,1},
{0,0},{0,0},{5,4},
{0,0},{0,0},{8,7},{9,8},{10,9},{11,10},{12,11},
{0,0},{0,0},{15,14},{16,15},{17,16},{18,17},{19,18},
{0,0},{0,0},{22,21},{23,22},{24,23},{25,24},{26,25},
{0,0},{0,0},{29,28},
{0,0},{0,0},{32,31}};

// 右移的位置
int rightit[34][2] =
{{0,0},
{2,3},{0,0},{0,0},
{5,6},{0,0},{0,0},
{8,9},{9,10},{10,11},{11,12},{12,13},{0,0},{0,0},
{15,16},{16,17},{17,18},{18,19},{19,20},{0,0},{0,0},
{22,23},{23,24},{24,25},{25,26},{26,27},{0,0},{0,0},
{29,30},{0,0},{0,0},
{32,33},{0,0},{0,0}};

//down 1,up 2,left 3,right 4;
bool Node::down(int id,Node& next)
{
 if(downit[id][0] == 0){        // 由于移动后出界不能移
  return false;
 }else{
  if(c[downit[id][0]] == 1 && c[downit[id][1]] == 0){ 
   next = *this;        // 拷贝当前
   next.key ++;

   // 移动后的棋局
   next.c[id] = 0;
   next.c[downit[id][0]] = 0;
   next.c[downit[id][1]] = 1;

   // 记录移动到达的步数
   next.moveid[0] ++;
   next.moveid[next.moveid[0]] = id ;
   next.dirction[next.moveid[0]] = 1;

   return true;
  }else{           // 由于移动后位置不允许不能移
   return false;
  }
 }
}

bool Node::up(int id,Node& next)
{
 if(upit[id][0] == 0){        // 由于移动后出界不能移
  return false;
 }else{
  if(c[upit[id][0]] == 1 && c[upit[id][1]] == 0){ 
   next = *this;        // 拷贝当前
   next.key ++;

   // 移动后的棋局
   next.c[id] = 0;
   next.c[upit[id][0]] = 0;
   next.c[upit[id][1]] = 1;

   // 记录移动到达的步数
   next.moveid[0] ++;
   next.moveid[next.moveid[0]] = id ;
   next.dirction[next.moveid[0]] = 2;
   return true;
  }else{           // 由于移动后位置不允许不能移
   return false;
  }
 }
}

bool Node::left(int id,Node& next)
{
 if(leftit[id][0] == 0){         // 由于移动后出界不能移
  return false;
 }else{
  if(c[leftit[id][0]] == 1 && c[leftit[id][1]] == 0){ 
   next = *this;         // 拷贝
   next.key ++;

   // 移动后的棋局
   next.c[id] = 0;
   next.c[leftit[id][0]] = 0;
   next.c[leftit[id][1]] = 1;

   // 记录移动到达的步数
   next.moveid[0] ++;
   next.moveid[next.moveid[0]] = id ;
   next.dirction[next.moveid[0]] = 3;
   return true;
  }else{            // 由于移动后位置不允许不能移
   return false;
  }
 }
}

bool Node::right(int id,Node& next)
{
 if(rightit[id][0] == 0){         
  return false;
 }else{
  if(c[rightit[id][0]] == 1 && c[rightit[id][1]] == 0){ 
   next = *this;          // 拷贝
   next.key ++;

   // 移动后的棋局
   next.c[id] = 0;
   next.c[rightit[id][0]] = 0;
   next.c[rightit[id][1]] = 1;

   // 记录移动到达的步数
   next.moveid[0] ++;
   next.moveid[next.moveid[0]] = id ;
   next.dirction[next.moveid[0]] = 4;
   return true;
  }else{
   return false;
  }
 }
}

Node::Node()
{
 memset(c,0,sizeof(c));
 moveid[0] = 0;
}

bool Node::operator> (const Node &op2) const
{
 if(key>op2.key)
  return
   true;
  else
   return
    false;
}
bool Node::operator< (const Node &op2) const
{
 if(key<op2.key)
  return
   true;
  else
   return
    false;
}
bool Node::operator>=(const Node &op2) const
{
 if(key>=op2.key)
  return
   true ;
  else
   return
    false;
}
bool Node::operator==(const Node &op2) const
{
 for(int i=1;i<=33;i++){
  if(c[i]!=op2.c[i])
   return false;
 }
 return true;
}
void Node::output(ostream &out) const
{
 out<<"/n--------------------------各步走法如下-------------------/n";
 Node tmp = *this;
 for(int i=1;i<=33;i++)
  tmp.c[i] = 1;
 tmp.c[17] = 0;
 out<<tmp;
 for(int i=1;i<=31;i++){
  if(tmp.dirction[i] == 1){
   tmp.c[tmp.moveid[i]] = 0;
   tmp.c[downit[tmp.moveid[i]][0]] = 0;
   tmp.c[downit[tmp.moveid[i]][1]] = 1;
   out<<"移动棋子:"<<tmp.moveid[i]<<"号,移动方向:向下./n";
  }else if(tmp.dirction[i] == 2){
   tmp.c[tmp.moveid[i]] = 0;
   tmp.c[upit[tmp.moveid[i]][0]] = 0;
   tmp.c[upit[tmp.moveid[i]][1]] = 1;
   out<<"移动棋子:"<<tmp.moveid[i]<<"号,移动方向:向上./n";
  }else if(tmp.dirction[i] == 3){
   tmp.c[tmp.moveid[i]] = 0;
   tmp.c[leftit[tmp.moveid[i]][0]] = 0;
   tmp.c[leftit[tmp.moveid[i]][1]] = 1;
   out<<"移动棋子:"<<tmp.moveid[i]<<"号,移动方向:向左./n";
  }else if(tmp.dirction[i] == 4){
   tmp.c[tmp.moveid[i]] = 0;
   tmp.c[rightit[tmp.moveid[i]][0]] = 0;
   tmp.c[rightit[tmp.moveid[i]][1]] = 1;
   out<<"移动棋子:"<<tmp.moveid[i]<<"号,移动方向:向右./n";
  }
  out<<tmp;
 }
  out<<"/n----------------------移动完成-----------------------/n";
}

ostream &operator <<(ostream &output,const Node &op2)
{
 output<<"    "<<op2.c[1]<<" "<<op2.c[2]<<" "<<op2.c[3]<<" /n";
 output<<"    "<<op2.c[4]<<" "<<op2.c[5]<<" "<<op2.c[6]<<" /n";
 for(int i=1;i<=3;i++){
  for(int j=7*i;j<7*(i+1);j++){
   output<<op2.c[j]<<" ";
  }
  output<<"/n";
 }
 output<<"    "<<op2.c[28]<<" "<<op2.c[29]<<" "<<op2.c[30]<<" /n";
 output<<"    "<<op2.c[31]<<" "<<op2.c[32]<<" "<<op2.c[33]<<" /n";
 return output;
}
/*
CODY BY 01120136 我的BLOG AT 2004.10.9
独立钻石棋问题, 深度优先搜索,尽量清除重复点
棋盘编号布局如下:
      01 02 03
   04 05 06
07 08 09 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
   28 29 30
   31 32 33
*/

#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include "Node.h"
using namespace std;

vector<Node> open;    // OPEN集  
vector<Node> closed;   // CLOSED集
vector<Node>::iterator iter; 

// 判断next结点是否已扩展过,是返回true,否则false
bool extended(Node &next);
// 搜索解
void search();

int main(void)
{

 search();
 system("pause");
 return 0;
}

void search()
{
 // 初始化
 Node first;
 for(int i=1;i<=33;i++){
  first.c[i] = 1;
 }
 first.c[17] = 0;
 first.key = 0;
 open.push_back(first);

 // 开始循环
 while(!open.empty()){
  cout<<"正在搜索......         已扩展结点:"<<closed.size()<<"/n";
  make_heap(open.begin(),open.end());   // 建最大堆
  pop_heap(open.begin(),open.end());   // 取走堆首元素,可为启发式搜索准备
  Node tmp = open.back();     
  open.pop_back();

  // 看所取节点是否为目标节点
  if(tmp.moveid[0] >= 31 && tmp.c[17] == 1){
   tmp.output(cout);      // 输出解并返回
   ofstream out("out.txt");
   tmp.output(out);      
   return ;
  }

  // 若不是则生成所有的子状态
  Node next;
  bool hadit;
  for(int i = 1;i <= 33 ;i++){
   if(tmp.c[i] != 0){
    if( tmp.down(i,next)){
     if(extended(next) == false){ // 还没扩展过
      open.push_back(next); 
     }
    }
    if( tmp.up(i,next)){
     if(extended(next) == false){ // 还没扩展过
      open.push_back(next);
     }
    }
    if( tmp.left(i,next)){
     if(extended(next) == false){ // 还没扩展过
      open.push_back(next);
     }
    }
    if( tmp.right(i,next)){
     if(extended(next) == false){ // 还没扩展过
      open.push_back(next);
     }
    }
   }
  }
  // 将刚才取出的open点放入closed表
  closed.push_back(tmp);
 }
}

bool extended(Node &next)
{
 // 若next在closed中,即已扩展过了,返回true
 for(iter = closed.begin();iter !=closed.end();iter++){
  if(*iter == next){
   return true;
  }
 }
 // 若已在open集中,则返回true;
 for(iter = open.begin();iter !=open.end();iter++){
  if(*iter == next){
   return true;
  }
 }
 // 都没有则返回false
 return false;
}

 

 

 

阅读全文
0 0

相关文章推荐

img
取 消
img