排列宝石问题回溯算法
2015-11-21 19:16
381 查看
问题描述:
现有n种不同形状的宝石,每种n颗,共n*n颗。同一形状的n颗宝石分别具有n种不同的颜色c1,c2,…,cn中的一种颜色。欲将这n*n颗宝石排列成n行n列的一个方阵,使方阵中每一行和每一列的宝石都有n种不同的形状和n种不同颜色。是设计一个算法,计算出对于给定的n,有多少种不同的宝石排列方案。
问题解决:
用回溯算法解决问题的一般步骤为:
step 1、定义一个解空间,它包含问题的解。
step 2、利用适于搜索的方法组织解空间。
step 3、利用深度优先法搜索解空间。
step 4、利用限界函数避免移动到不可能产生解的子空间。
用回溯法解排列宝石问题,用完全n叉树表示解空间,可行性约束place减去不满足要求约束的子树。
<1>、算法思路:
利用回溯算法backtrack,当行号(列号)大于n时,算法搜索至叶节点,当前找到可行性方案,sum+1;否者当前扩展节点是解空间中的内部节点,找出未排列的宝石,用place检验当前宝石是否可以放置,并以深度优先的方式递归的对可行子树搜索。
<2>、算法程序:
现有n种不同形状的宝石,每种n颗,共n*n颗。同一形状的n颗宝石分别具有n种不同的颜色c1,c2,…,cn中的一种颜色。欲将这n*n颗宝石排列成n行n列的一个方阵,使方阵中每一行和每一列的宝石都有n种不同的形状和n种不同颜色。是设计一个算法,计算出对于给定的n,有多少种不同的宝石排列方案。
问题解决:
用回溯算法解决问题的一般步骤为:
step 1、定义一个解空间,它包含问题的解。
step 2、利用适于搜索的方法组织解空间。
step 3、利用深度优先法搜索解空间。
step 4、利用限界函数避免移动到不可能产生解的子空间。
用回溯法解排列宝石问题,用完全n叉树表示解空间,可行性约束place减去不满足要求约束的子树。
<1>、算法思路:
利用回溯算法backtrack,当行号(列号)大于n时,算法搜索至叶节点,当前找到可行性方案,sum+1;否者当前扩展节点是解空间中的内部节点,找出未排列的宝石,用place检验当前宝石是否可以放置,并以深度优先的方式递归的对可行子树搜索。
<2>、算法程序:
#include<iostream> #include<fstream> using namespace std; class Diamond { public: int color;//颜色编号 int shape;//形状编号 int use;//是否已经排列,默认1为未排列 }; //初始化n*n个宝石 void init(Diamond *a,int n) { //分别为n种颜色各具n种形状的宝石赋初值 for(int i=1;i<=n*n;i++) { a[i].color=(i-1)/n+1; a[i].shape=(i-1)%n+1; a[i].use=1; } } //检验宝石是否可放 bool place(Diamond *a,int **s,int x,int y) { for(int i=1;i<y;i++)//判断行中是否有颜色形状重复 { if(a[s[x][i]].color==a[s[x][y]].color || a[s[x][i]].shape==a[s[x][y]].shape) return 0; } for(int j=1;j<x;j++)//判断列中是否有颜色形状重复 { if(a[s[j][y]].color==a[s[x][y]].color || a[s[j][y]].shape==a[s[x][y]].shape) return 0; } return 1; } //用回溯法递归搜索 void backtrack(Diamond *a,int **s,int t,int n,int &sum) { int x,y; x=(t-1)/n+1;//存放的行号 y=(t-1)%n+1;//存放的列号 if(x>n)sum++; else for(int i=1;i<=n*n;i++) { if(a[i].use)//当前宝石未排列 { s[x][y]=i; if(place(a,s,x,y))//当前宝石颜色形状不重复 { a[i].use=0; backtrack(a,s,t+1,n,sum); a[i].use=1; } } } } //计算当前宝石排列的方案数 int numDiamond(int n) { Diamond *a=new Diamond[n*n+1]; init(a,n); int sum=0; int **s=new int*[n+1]; for(int m=1;m<=n;m++) s[m]=new int[n+1]; backtrack(a,s,1,n,sum); return sum; } int main() { //读出输入文件中的数据 fstream fin; fin.open("input.txt",ios::in); if(fin.fail()) { cout<<"File does not exist!"<<endl; cout<<"Exit program"<<endl; return 0; } int n; fin>>n; //调用函数 int number=numDiamond(n); cout<<"宝石排列的方案数为:"<<number<<"种"<<endl; //将结果数据写入到输出文件 fstream fout; fout.open("output.txt",ios::out); fout<<number; fin.close(); fout.close(); system("pause"); return 0; }
相关文章推荐
- 0023网络爬虫的基本原理(一)
- jni c语言使用指针交换两个值
- python入门(1)
- iPhone 尺寸
- 关于总结
- 从Mysql某一表中随机读取n条数据的SQL查询语句
- linux基础命令
- iOS程序启动的过程
- 快速排序(已优化) -- C语言
- 灭灯小游戏 UI代码
- linux c++知识
- oracle中有关表的操作
- Android 窗口添加机制系列3-代码实例
- 1004. Counting Leaves (30)
- 我与大话设计模式之代码篇(一)-----简单工厂
- poj 3352 Road Construction(双联通)
- HSSFWorkBooK 设置excel样式用法
- Test
- 安卓图表引擎AChartEngine(三) - 示例源码折线图、饼图和柱状图
- bash基本语法