puzzle算法
⑴ 3*3 型的拼图界面。数字1~8 和一个空格。要实现能拼图功能~~大概的算法是怎样的!!
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<time.h>
int main(void)
{
void swap(int *a,int *b); //子函数声明
int i,j,k,n,puzzle[81]={0},parity[81]={0}; //拼图数组和奇偶性数组
char ch; //用来记录拼图数组可以转换成顺序矩阵,还是逆序矩阵
printf("游戏说明\n");
printf("↑ :数字向上 ↓ :数字向下\n");
printf("← :数字向左 → :数字向右\n");
printf("Esc:退出程序 Space:重置矩阵\n");
printf("\n");
loop1:
printf("难度设置\nn:");
scanf("%d",&n);
loop2:
system("cls"); //清屏
srand((unsigned)time(NULL)); //动态获取数据
for(i=0;i<=n*n-1;i++)
{
loop3:
k=rand()%(n*n); //记录新的数据
for(j=0;j<i;j++) //和旧的数据进行比较,当新的数据
if(puzzle[j]==k) goto loop3; //出现过时,重新获取
if(j==i)
{
puzzle[j]=k; //当新的数据和旧的数据都不同时,将
} //数据放入拼图数组中
}
for(i=0;i<=n*n-1;i++)
{
parity[i]=puzzle[i]; //将拼图数组赋予奇偶性数组
}
for(i=0;i<=n*n-1;i++)
{
if(parity[i]==0) break; //找出奇偶性数组中0(空格)的位置
}
k=i;
for(j=1;j<=i/n;j++) //将0(空格)换到第1行
{
swap(&parity[k],&parity[k-n]);
k=k-n; //更新奇偶性数组中0(空格)的位置
}
for(j=1;j<=i%n;j++) //将0(空格)换到第1列
{
swap(&parity[k],&parity[k-1]);
k=k-1; //更新奇偶性数组中0(空格)的位置
}
k=0;
for(i=0;i<=n*n-1;i++)
for(j=i;j<=n*n-1;j++)
{
if(parity[i]>parity[j]) k++; //求奇偶性数组的“逆序数和”
}
if(k%2==0) printf("%d\n顺序矩阵",n),ch='0'; //“逆序数和”为偶数时,是顺序矩阵
else printf("%d\n逆序矩阵",n),ch='1'; //“逆序数和”为奇数时,是逆序矩阵
printf("\n");
for(i=0;i<=n*n-1;i++) //打印拼图数组
{
if(puzzle[i]==0) printf("%*c",n,' '); //是0(空格)的位置,打印空格
else printf("%-*d",n,puzzle[i]); //是数字的位置,打印对应宽度的数字
if((i+1)%n==0&&i!=n*n-1) printf("\n"); //每打印n个数字,换一行打印
}
while(1)
{
for(i=0;i<=n*n-1;i++)
{
if(puzzle[i]==0) break; //记录拼图数组中0(空格)的位置
}
switch(getch())
{
case 72:if( i<n*(n-1)) swap(&puzzle[i],&puzzle[i+n]);break; //数字向上
case 80:if( i>1*(n-1)) swap(&puzzle[i],&puzzle[i-n]);break; //数字向下
case 75:if((i+1)%n!=0) swap(&puzzle[i],&puzzle[i+1]);break; //数字向左
case 77:if((i+0)%n!=0) swap(&puzzle[i],&puzzle[i-1]);break; //数字向右
case 27:exit(0); //退出程序
case 32:goto loop2; //重置矩阵
}
system("cls"); //清屏
switch(ch)
{
case '0':printf("%d\n顺序矩阵\n",n);break; //完成拼图的最终目标
case '1':printf("%d\n逆序矩阵\n",n);break; //完成拼图的最终目标
}
for(i=0;i<=n*n-1;i++)
{
if(puzzle[i]==0) printf("%*c",n,' '); //是0(空格)的位置,打印空格
else printf("%-*d",n,puzzle[i]); //是数字的位置,打印对应宽度的数字
if((i+1)%n==0&&i!=n*n-1) printf("\n"); //每打印n个数字,换一行打印
}
for(i=0;i<=n*n-3;i++)
{
if(puzzle[i]!=i) break; //判断拼图数组是否为顺序矩阵或逆序矩阵
}
if(i==n*n-2)
{ //是顺序矩阵或是逆序矩阵时,完成拼图
printf("\n恭喜你,拼图完成了!\n"); //打印完成标志
printf("Continue(y/n)?");
if(getch()=='y')
{
system("cls"); //清屏
goto loop1; //重新开始
}
else
{
exit(0); //退出程序
}
}
}
getch(); //显示运行结果
return(0); //正常运行返回0
}
void swap(int *a,int *b)
{
int c;
c=*a;
*a=*b;
*b=c;
}
⑵ 谁有用A* search/算法 解16puzzle/8puzzle/25puzzle 的详细算法或者代码
首先是规则,其次是模拟运行,校验。最后是优化。
我看优化的要点是优先检验小数字是否还需移动。可以把已经一动完成的小块锁住,这样就可以排除大量没用的移动。
⑶ 启发式算法的新算法
如何找到一个分叉率较少又通用的合理启发式算法,已被人工智能社群深入探究过。 他们使用几种常见技术:
部分问题的解答的代价通常可以评估解决整个问题的代价,通常很合理。例如一个10-puzzle拼盘,解题的代价应该与将1到5的方块移回正确位置的代价差不多。通常解题者会先建立一个储存部份问题所需代价的模式数据库(pattern database)以评估问题。 解决较易的近似问题通常可以拿来合理评估原先问题。例如曼哈顿距离是一个简单版本的n-puzzle问题,因为我们假设可以独立移动一个方块到我们想要的位置,而暂不考虑会移到其他方块的问题。 给我们一群合理的启发式函式h1(n),h2(n),...,hi(n),而函式h(n) = max{h1(n),h2(n),...,hi(n)}则是个可预测这些函式的启发式函式。 一个在1993年由A.E. Prieditis写出的程式ABSOLVER就运用了这些技术,这程式可以自动为问题产生启发式算法。ABSOLVER为8-puzzle产生的启发式算法优于任何先前存在的!而且它也发现了第一个有用的解魔术方块的启发式程式。
⑷ 谁来看下我的迷宫算法(还没做完)为啥就空指针了
我来给你分析一下,首先你在RunPuzzle里通过main方法来启动整个程序。在main方法中,首先定义了一个字符串数组,然后通过这个字符串数组来创建一个puzzle,下面我们到puzzle的构造方法里看看你是怎么创建这个puzzle的,首先呢,你创建了一个9*9的Lattice二维数组L,注意你这个时候并没有对这个数组L里的每一个元素赋值为某个真正的Lattice对象的引用,说的更明确一点,现在这个二维数组里全部都是null,所以接下来你的代码在二重循环里便直接用“L[i][j].setPos(i, j);”来调用setPos当然会出现空指针异常了,因为这时L[i][j]全部都是null,明白了么?
请楼主给我加分吧,哈哈
⑸ 启发式算法的最短路径
所谓的最短路径问题有很多种意思, 在这里启发式指的是一个在一个搜寻树的节点上定义的函数h(n),用于评估从此节点到目标节点最便宜的路径。启发式通常用于资讯充分的搜寻算法,例如最好优先贪婪算法与A*。最好优先贪婪算法会为启发式函数选择最低代价的节点;A*则会为g(n) + h(n)选择最低代价的节点,此g(n)是从起始节点到目前节点的路径的确实代价。如果h(n)是可接受的(admissible)意即h(n)未曾付出超过达到目标的代价,则A*一定会找出最佳解。
最能感受到启发式算法好处的经典问题是n-puzzle。此问题在计算错误的拼图图形,与计算任两块拼图的曼哈顿距离的总和以及它距离目的有多远时,使用了本算法。注意,上述两条件都必须在可接受的范围内。
⑹ C++编程,用A*算法重排九宫图(eight-puzzle)
POJ 有原题
⑺ tree-puzzle
序列比对建议用ClustalX
建NJ或MP树,用MEGA就可以了,非常方便
若要建ML树推荐用phyML
建Bayes树推荐用Parallel MrBayes @ BioHPC
如果不是专业建树的话,MEGA足够用了,建议参考下面这篇文章:
一、引言
开始动笔写这篇短文之前,我问自己,为什么要写这样的文章?写这样的文章有实际的意义吗?我希望能够解决什么样的问题?带着这样的疑惑,我随手在丁香园(DXY)上以关键字“进化 分析 求助”进行了搜索,居然有289篇相关的帖子(2006年9月12日)。而以关键字“进化分析”和“进化”为关键字搜索,分别找到2,733和7,724篇相关的帖子。考虑到有些帖子的内容与分子进化无关,这里我保守的估计,大约有 3,000~4,000篇帖子的内容,是关于分子进化的。粗略地归纳一下,我大致将提出的问题分为下述的几类:
1.涉及基本概念
例如,“分子进化与生物进化是不是一个概念”,“关于微卫星进化模型有没有什么新的进展”以及“关于Kruglyak的模型有没有改进的出现”,等等。
2.关于构建进化树的方法的选择
例如,“用boostrap NJ得到XX图,请问该怎样理解?能否应用于文章?用boostrap test中的ME法得到的是XXX树,请问与上个树比,哪个更好”,等等。
3.关于软件的选择
例如,“想做一个进化树,不知道什么软件能更好的使用且可以说明问题,并且有没有说明如何做”,“拿到了16sr RNA数据,打算做一个系统进化树分析,可是原来没有做过这方面的工作啊,都要什么软件”,“请问各位高手用ClustalX做出来的进化树与 phylip做的有什么区别”,“请问有做过进化树分析的朋友,能不能提供一下,做树的时候参数的设置,以及代表的意思。还有各个分支等数值的意思,说明的问题等”,等等。
4.蛋白家族的分类问题
例如,“搜集所有的关于一个特定domain的序列,共141条,做的进化树不知具体怎么分析”,等等。
5.新基因功能的推断
例如,“根据一个新基因A氨基酸序列构建的系统发生树,这个进化树能否说明这个新基因A和B同源,属于同一基因家族”,等等。
6.计算基因分化的年代
例如,“想在基因组水平比较两个或三个比较接近物种之间的进化年代的远近,具体推算出他们之间的分歧时间”,“如何估计病毒进化中变异所需时间”,等等。
7.进化树的编辑
例如生成的进化树图片,如何进行后续的编辑,比如希望在图片上标注某些特定的内容,等等。
由于相关的帖子太多,作者在这里对无法阅读全部的相关内容而致以歉意。同时,作者归纳的这七个问题也并不完全代表所有的提问。对于问题1所涉及到的基本的概念,作者推荐读者可参考由Masatoshi Nei与Sudhir Kumar所撰写的《分子进化与系统发育》(Molecular Evolution and Phylogenetics)一书,以及相关的分子进化方面的最新文献。对于问题7,作者之一lylover一般使用Powerpoint进行编辑,而 Photoshop、Illustrator及Windows自带的画图工具等都可以使用。
这里,作者在这里对问题2-6进行简要地解释和讨论,并希望能够初步地解答初学者的一些疑问。
二、方法的选择
首先是方法的选择。基于距离的方法有UPGMA、ME(Minimum Evolution,最小进化法)和NJ(Neighbor-Joining,邻接法)等。其他的几种方法包括MP(Maximum parsimony,最大简约法)、ML(Maximum likelihood,最大似然法)以及贝叶斯(Bayesian)推断等方法。其中UPGMA法已经较少使用。
一般来讲,如果模型合适,ML的效果较好。对近缘序列,有人喜欢MP,因为用的假设最少。MP一般不用在远缘序列上,这时一般用NJ或ML。对相似度很低的序列,NJ往往出现Long-branch attraction(LBA,长枝吸引现象),有时严重干扰进化树的构建。贝叶斯的方法则太慢。对于各种方法构建分子进化树的准确性,一篇综述(Hall BG. Mol Biol Evol 2005, 22(3):792-802)认为贝叶斯的方法最好,其次是ML,然后是MP。其实如果序列的相似性较高,各种方法都会得到不错的结果,模型间的差别也不大。
对于NJ和ML,是需要选择模型的。对于各种模型之间的理论上的区别,这里不作深入的探讨,可以参看Nei的书。对于蛋白质序列以及DNA序列,两者模型的选择是不同的。以作者的经验来说,对于蛋白质的序列,一般选择Poisson Correction(泊松修正)这一模型。而对于核酸序列,一般选择Kimura 2-parameter(Kimura-2参数)模型。如果对各种模型的理解并不深入,作者并不推荐初学者使用其他复杂的模型。
Bootstrap几乎是一个必须的选项。一般Bootstrap的值>70,则认为构建的进化树较为可靠。如果Bootstrap的值太低,则有可能进化树的拓扑结构有错误,进化树是不可靠的。
对于进化树的构建,如果对理论的了解并不深入,作者推荐使用缺省的参数。需要选择模型的时候(例如用NJ或者ML建树),对于蛋白序列使用Poisson Correction模型,对于核酸序列使用Kimura-2参数模型。另外需要做Bootstrap检验,当Bootstrap值过低时,所构建的进化树其拓扑结构可能存在问题。并且,一般推荐用两种不同的方法构建进化树,如果所得到的进化树类似,则结果较为可靠。
三、软件的选择
表1中列出了一些与构建分子进化树相关的软件。
构建NJ树,可以用PHYLIP(写得有点问题,例如比较慢,并且Bootstrap检验不方便)或者MEGA。MEGA是Nei开发的方法并设计的图形化的软件,使用非常方便。作者推荐MEGA软件为初学者的首选。虽然多雪列比对工具ClustalW/X自带了一个NJ的建树程序,但是该程序只有p- distance模型,而且构建的树不够准确,一般不用来构建进化树。
构建MP树,最好的工具是PAUP,但该程序属于商业软件,并不对学术免费。因此,作者并不建议使用PAUP。而MEGA和PHYLIP也可以用来构建进化树。这里,作者推荐使用MEGA来构建MP树。理由是,MEGA是图形化的软件,使用方便,而PHYLIP则是命令行格式的软件,使用较为繁琐。对于近缘序列的进化树构建,MP方法几乎是最好的。
构建ML树可以使用PHYML,速度最快。或者使用Tree-puzzle,速度也较快,并且该程序做蛋白质序列的进化树效果比较好。而PAML则并不适合构建进化树。ML的模型选择是看构出的树的likelihood值,从参数少,简单的模型试起,到likelihood值最大为止。ML也可以使用 PAUP或者PHYLIP来构建。这里作者推荐的工具是BioEdit。BioEdit集成了一些PHYLIP的程序,用来构建进化树。Tree- puzzle是另外一个不错的选择,不过该程序是命令行格式的,需要学习DOS命令。PHYML的不足之处是没有win32的版本,只有适用于64位的版本,因此不推荐使用。值得注意的是,构建ML树,不需要事先的多序列比对,而直接使用FASTA格式的序列即可。
贝叶斯的算法以MrBayes为代表,不过速度较慢。一般的进化树分析中较少应用。由于该方法需要很多背景的知识,这里不作介绍。
表1 构建分子进化树相关的软件
软件 网址 说明
ClustalX 图形化的多序列比对工具
ClustalW 命令行格式的多序列比对工具
GeneDoc 多序列比对结果的美化工具(可以导入fasta格式的文件,出来的图可用于发表,我用过)
BioEdit 序列分析的综合工具
MEGA 图形化、集成的进化分析工具,不包括ML
PAUP 商业软件,集成的进化分析工具
PHYLIP 免费的、集成的进化分析工具
PHYML 最快的ML建树工具
PAML ML建树工具
Tree-puzzle 较快的ML建树工具
MrBayes 基于贝叶斯方法的建树工具
MAC5 基于贝叶斯方法的建树工具
TreeView 进化树显示工具
(加红色标注的为最通用的分析软件)
需要注意的几个问题是,其一,如果对核酸序列进行分析,并且是CDS编码区的核酸序列,一般需要将核酸序列分别先翻译成氨基酸序列,进行比对,然后再对应到核酸序列上。这一流程可以通过MEGA 3.0以后的版本实现。MEGA3现在允许两条核苷酸,先翻成蛋白序列比对之后再倒回去,做后续计算。
其二,无论是核酸序列还是蛋白序列,一般应当先做成 FASTA格式。FASTA格式的序列,第一行由符号“>”开头,后面跟着序列的名称,可以自定义,例如user1,protein1等等。将所有的FASTA格式的序列存放在同一个文件中。文件的编辑可用Windows自带的记事本工具,或者EditPlus(google搜索可得)来操作。
另外,构建NJ或者MP树需要先将序列做多序列比对的处理。作者推荐使用ClustalX进行多序列比对的分析。多序列比对的结果有时需要后续处理并应用于文章中,这里作者推荐使用GeneDoc工具。而构建ML树则不需要预先的多序列比对。
因此,作者推荐的软件组合为:MEGA + ClustalX + GeneDoc + BioEdit。
四、数据分析及结果推断
一般碰到的几类问题是,(1)推断基因/蛋白的功能;(2)基因/蛋白家族分类;(3)计算基因分化的年代。关于这方面的文献非常多,这里作者仅做简要的介绍。
推断基因/蛋白的功能,一般先用Blast工具搜索同一物种中与不同物种的同源序列,这包括直向同源物(ortholog)和旁系同源物(paralog)。如何界定这两种同源物,网上有很多详细的介绍,这里不作讨论。然后得到这些同源物的序列,做成FASTA格式的文件。一般通过NJ构建进化树,并且进行Bootstrap分析所得到的结果已足够。如果序列近缘,可以再使用MP构建进化树,进行比较。如果序列较远源,则可以做ML树比较。使用两种方法得到的树,如果差别不大,并且Bootstrap总体较高,则得到的进化树较为可靠。
基因/蛋白家族分类。这方面可以细分为两个问题。一是对一个大的家族进行分类,另一个就是将特定的一个或多个基因/蛋白定位到已知的大的家族上,看看属于哪个亚家族。例如,对驱动蛋白(kinesin)超家族进行分类,属于第一个问题。而假如得到一个新的驱动蛋白的序列,想分析该序列究竟属于驱动蛋白超家族的14个亚家族中的哪一个,则属于后一个问题。这里,一般不推荐使用MP的方法。大多数的基因/蛋白家族起源较早,序列分化程度较大,相互之间较为远源。这里一般使用NJ、ME或者ML的方法。
计算基因分化的年代。这个一般需要知道物种的核苷酸替代率。常见物种的核苷酸替代率需要查找相关的文献。这里不作过多的介绍。一般对于这样的问题,序列多数是近缘的,选择NJ或者MP即可。
如果使用MEGA进行分析,选项中有一项是“Gaps/Missing Data”,一般选择“Pairwise Deletion”。其他多数的选项保持缺省的参数。
五、总结
在实用中,只要方法、模型合理,建出的树都有意义,可以任意选择自己认为好一个。最重要的问题是:你需要解决什么样的问题?如果分析的结果能够解决你现有的问题,那么,这样的分析足够了。因此,在做进化分析前,可能需要很好的考虑一下自己的问题所在,这样所作的分析才有针对性。
六、致谢
本文由mediocrebeing在2005年9月8日所发起的讨论《关于建树的经验》扩充、修改而来。文章的作者按原贴ID出现先后排名,由 lylover执笔。作者同时感谢所有参与讨论的战友。作者lylover感谢中国科大细胞动力学实验室的金长江博士所给的一些有益的建议。
来源:丁香园(mediocrebeing, rodger, lylover , klaus, oldfish, yzwpf)
⑻ 扑克24算法
我有两种,一种是随机搜索法,一种是用排列组合的方法穷举:第二种写的时候复杂了一点,呵呵:下面程序有两种方法,你看看互相的调用吧。/* Calcu24.cpp : Defines the entry point for the console application.
weizengke
2010-6-6 随机解法
2010-10-7 全局搜索法
*/#include "stdafx.h"
#include "conio.h"
#include "stdlib.h"
#include "time.h"
#include "math.h"
#include "string.h"
#include "iostream.h"
/*
从一副扑克牌中,任取4张。
2-10 按其点数计算(为了表示方便10用T表示),J,Q,K,A 统一按 1 计算
要求通过加减乘除四则运算得到数字 24。
本程序可以随机抽取纸牌,并用试探法求解。
*/
int s[21][4]={-1};
int sum=0;
void GivePuzzle(char* buf)
{
char card[] = {'A','2','3','4','5','6','7','8','9','T','J','Q','K'};
for(int i=0; i<4; i++){
buf[i] = card[rand() % 13];
}
}void SetPuzzle(char *buf)
{
scanf("%c %c %c %c",&buf[0],&buf[1],&buf[2],&buf[3]);
}
void shuffle(char * buf)
{
for(int i=0; i<5; i++){
int k = rand() % 4;
char t = buf[k];
buf[k] = buf[0];
buf[0] = t;
}
}
int GetCardValue(int c)
{
if(c=='T') return 10;
if(c>='0' && c<='9') return c - '0';
return 1;
}
char GetOper(int n)
{
switch(n)
{
case 0:
return '+';
case 1:
return '-';
case 2:
return '*';
case 3:
return '/';
} return ' ';
}double MyCalcu(double op1, double op2, int oper)
{
switch(oper)
{
case 0:
return op1 + op2;
case 1:
return op1 - op2;
case 2:
return op1 * op2;
case 3:
if(fabs(op2)>0.0001)
return op1 / op2;
else
return 100000;
} return 0;
}
void MakeAnswer(char* answer, int type, char* question, int* oper)
{
char p[4][3];
for(int i=0; i<4; i++)
{
if( question[i] == 'T' )
strcpy(p[i], "10");
else
sprintf(p[i], "%c", question[i]);
}
switch(type)
{
case 0:
sprintf(answer, "%s %c (%s %c (%s %c %s))",
p[0], GetOper(oper[0]), p[1], GetOper(oper[1]), p[2], GetOper(oper[2]), p[3]);
break;
case 1:
sprintf(answer, "%s %c ((%s %c %s) %c %s)",
p[0], GetOper(oper[0]), p[1], GetOper(oper[1]), p[2], GetOper(oper[2]), p[3]);
break;
case 2:
sprintf(answer, "(%s %c %s) %c (%s %c %s)",
p[0], GetOper(oper[0]), p[1], GetOper(oper[1]), p[2], GetOper(oper[2]), p[3]);
break;
case 3:
sprintf(answer, "((%s %c %s) %c %s) %c %s",
p[0], GetOper(oper[0]), p[1], GetOper(oper[1]), p[2], GetOper(oper[2]), p[3]);
break;
case 4:
sprintf(answer, "(%s %c (%s %c %s)) %c %s",
p[0], GetOper(oper[0]), p[1], GetOper(oper[1]), p[2], GetOper(oper[2]), p[3]);
break;
}
}
bool TestResolve(char* question, int* oper, char* answer)
{
// 等待考生完成
int type[5]={0,1,2,3,4};//计算类型
double p[4];
double sum=0;
for(int i=0; i<4; i++) //循环取得点数
{
p[i]=GetCardValue(int(question[i]));
} for(i=0;i<5;i++)
{
MakeAnswer(answer,type[i],question,oper); //获取可能的答案
//printf("Doing:%s\n", answer);
switch(type[i])
{
case 0:
sum=MyCalcu(p[0],MyCalcu( p[1],MyCalcu(p[2], p[3], oper[2]),oper[1]),oper[0]); //A*(B*(c*D))
break;
case 1:
sum=MyCalcu(p[0],MyCalcu(MyCalcu(p[1], p[2], oper[1]),p[3],oper[2]),oper[0]); //A*((B*C)*D)
break;
case 2:
sum=MyCalcu(MyCalcu(p[0], p[1], oper[0]),MyCalcu(p[2], p[3], oper[2]),oper[1]); // (A*B)*(C*D)
break;
case 3:
sum=MyCalcu(MyCalcu(MyCalcu(p[0], p[1], oper[0]),p[2],oper[1]),p[3],oper[2]); //((A*B)*C)*D
break;
case 4:
sum=MyCalcu(MyCalcu(p[0],MyCalcu(p[1], p[2], oper[1]),oper[0]),p[3],oper[2]); //(A*(B*C))*D
break;
}
if(sum==24) return true;
}
return false;
}
bool permNum(int* oper, int i,int N,char*question,char*answer) //递归实现重新排列数字、运算符
{
int j, k;
char tmp;
if(i < N)
{
for(j = i; j < N; j++)
{
tmp = question[j];
for(k = j; k > i; k--)
question[k] = question[k-1];
question[i] = tmp;
if( permNum(oper, i+1,N,question,answer)) return true;
for(k = i; k < j; k++)
question[k] = question[k+1];
question[j] = tmp;
}
}
else
{
//int type;
if( TestResolve(question, oper, answer) )
{
//getch();
return true;
}
}
return false;
}
bool perm(int* num, int i,int N,char*question,char*answer) //递归实现重新排列数字、运算符
{
int j, k, tmp;
if(i < N)
{
for(j = i; j < N; j++)
{
tmp = num[j];
for(k = j; k > i; k--)
num[k] = num[k-1];
num[i] = tmp;
if(perm(num, i+1,N,question,answer)) return true;
for(k = i; k < j; k++)
num[k] = num[k+1];
num[j] = tmp;
}
}
else
{
if (permNum(num,0,4,question,answer)) return true;
}
return false;
}
int ifcan(int str[4])
{
for(int i=0;i<sum;i++)
{
if(s[i][0]==str[0]&&s[i][1]==str[1]&&s[i][2]==str[2]) {
return 1;
}
}
s[i-1][0]=str[0];
s[i-1][1]=str[1];
s[i-1][2]=str[2];
sum++;
return 0;
}bool Chooseoper(int *oper,char*question,char*answer) //递归从四个运算符获取三个运算符
{
int n=3,m=12,i,j;
int oper1[12];
for (i=0;i<n;i++)
{
oper1[i]=i;
}
for (i=0;i<n;i++)
{
oper[i]=oper1[i]/3;
}
if (!ifcan(oper))
{
if(perm(oper,0,n,question,answer)) return true;
}
j=n-1;
while (1)
{
if (oper1[n-1]==m-1)
j--;
else j=n-1;
oper1[j]++;
for (i=j+1;i<n;i++)
oper1[i]=oper1[i-1]+1;
for (i=0;i<n;i++)
{
oper[i]=oper1[i]/3;
}
if (!ifcan(oper))
{
if(perm(oper,0,n,question,answer)) return true;
}
if (oper1[0]>=m-n)
break;
}
return false;
}
bool Try(int *oper,char*question,char* answer)
{
if(Chooseoper(oper,question,answer)) return true;
return false;
}
int main(int argc, char* argv[])
{
// 初始化随机种子
srand( (unsigned)time( NULL ) );
char buf1[4]; // 题目
char buf2[30]; // 解答
printf("***************************\n");
printf("计算24\n");
printf("A J Q K 均按1计算,其它按牌点计算,T 代表 10\n");
printf("目标是:通过四则运算组合出结果:24\n");
printf("Mode 1 of Give Puzzle: Rand to give puzzle\n");
printf("Else Type of Give Puzzle:Give by Youself \n");
printf("***************************\n\n");
int mode=1; //默认为1
printf("Mode:");
scanf("%d",&mode);
getchar();
printf("***************************\n");
for(;;)
{
if (mode==1)
{
GivePuzzle(buf1); // 出题模式1
}
else
{
printf("Num:");
SetPuzzle(buf1); //出题模式2
}
getchar();
printf("题目:");
for(int j=0; j<4; j++){
if( buf1[j] == 'T' )
printf("10 ");
else
printf("%c ", buf1[j]);
} printf("\n按任意键参考答案...\n");
getch(); int type[4];
if( Try(type, buf1,buf2) ) //1全局搜索解法,精确解
printf("参考:%s\n", buf2);
else
printf("无解...\n"); for (int i=0;i<sum;i++)
{
for(int j=0;j<3;j++)
s[i][j]=-1;
}
sum=0; printf("按任意键出下一题目,x 键退出...\n");
if( getch() == 'x' ) break; } return 0;
}
⑼ 数独算法
给你数独计算器:
http://blog.xunlei.com/web/category.html?uin=mianmiany1978&category_id=143
数独游戏:
http://blog.xunlei.com/web/category.html?uin=mianmiany1978&category_id=174
数独算法:
http://www.puzzle8.com/suku/news.asp
数独快速入门(上篇)
数独快速入门(中篇)
数独快速入门(下篇)
唯一解法
唯一候选数法
隐性三链数删减法
隐性数对删减法
三链列删减法
区块删减法
矩形顶点删减法
关键数删减法
补充:
合格的数独是只有唯一解。
而数独有难易度的分类,找一份报纸注意刊登的数独谜题是1星,还是5星。
在网络上,更分成容易题、进阶题、难题、极难题、超难题....
一般都是依据需要运用的技巧,而技巧是区分难易的。
数独不用猜测,解题全部是运用逻辑推理。
数独不用电脑程序分析,就可以解的题目是直观法数独题。
而超难题是需要电脑分析,及把全盘标示可选数,那是可选数谜题。
没有所谓解题通则。
1.直观解(一般报纸、书籍)
直观法技巧
直观法技巧 01 (容易级) 唯一解
直观法技巧 02 (容易级) 基本摒除
直观法技巧 03 (进阶级) 宫对行列摒除
直观法技巧 04 (进阶级) 行列对宫摒除
直观法技巧 05 (进阶级) 群组解法
直观法技巧 06 (困难级) X-Wing摒除法01
直观法技巧 06 (困难级) X-Wing摒除法02
直观法技巧 07 (困难级) 数偶摒除法
http://hi..com/kiwy07/blog/item/181fc482a153f3bd6c8119ab.html
2.可选数(以程序自动生成可选数)
Last value in block, row or column
Hidden Single in block
Hidden Single in row or column
Direct Pointing
Direct Claiming
Direct Hidden Pair
Naked Single
Direct Hidden Triplet
Pointing
Claiming
Naked Pair, X-Wing, Hidden Pair
Naked Triplet, Swordfish, Hidden Triplet
XY-Wing, XYZ-Wing
Unique rectangles and loops
Naked Quad, Jellyfish, Hidden Quad
Bivalue Universal Graves
Aligned Pair Exclusion
Bidirectioal X-Cycles and Y-Cycles
Forcing X-Chains
Forcing Chains, Bidirectional Cycles
Nishio
Cell/Region Forcing Chains
Dynamic Forcing Chains
http://diuf.unifr.ch/people/juillera/Sudoku/FAQ.html
通则无法解的题
直观难题
006589307
030602008
809703500
000891403
394265871
180374000
003026785
000458030
008037200
可选数极难题
970000000
003927000
008410709
300700400
060050070
007040003
105074900
000068507
786000042
不要把谜题解一次列出,而是找出下一步,及他的逻辑推理方法。
不要用猜测。
⑽ "最短路径优先算法"的优缺点
所谓的最短路径问题有很多种意思,
在这里启发式指的是一个在一个搜寻树的节点上定义的函数h(n),用于评估从此节点到目标节点最便宜的路径。启发式通常用于资讯充分的搜寻算法,例如最好优先贪婪算法与a*。最好优先贪婪算法会为启发式函数选择最低代价的节点;a*则会为g(n)
+
h(n)选择最低代价的节点,此g(n)是从起始节点到目前节点的路径的确实代价。如果h(n)是可接受的(admissible)意即h(n)未曾付出超过达到目标的代价,则a*一定会找出最佳解。
最能感受到启发式算法好处的经典问题是n-puzzle。此问题在计算错误的拼图图形,与计算任两块拼图的曼哈顿距离的总和以及它距离目的有多远时,使用了本算法。注意,上述两条件都必须在可接受的范围内。