所以我有这个程序应该解决C中的futoshiki拼图 从具有此格式的文本文件中加载:
5 0 | 0 | 0 | 0 | 0 - - - - v - - - - 0 > 0 | 0 | 0 | 3 - - - - - - - - - 0 | 0 < 2 | 0 | 0 - - - - v - - - - 0 | 0 | 0 | 0 | 4 ^ - v - - - - - - 0 | 0 | 0 | 0 | 0
其中5是矩阵的大小,并且与运算符<
,>
,^
,v
相邻的数字必须满足它们施加的条件,从文件中,行上的所有字符都用空格分隔
例如0 |
......
所以我设法加载文件,检查它是否满足数学运算符条件,但我坚持递归函数
我想知道的事情:
我是否选择了存储矩阵的正确方法,或者我应该从逻辑运算符中划分数字?
如何在矩阵上执行递归扩展,如何在某个步骤中跟踪使用的数字(如果我不得不回溯)?
例如。假设我到达index[j][j]
j<n
(矩阵的大小),从那里开始我将不得不递减j
(“触摸”)只有数字并检查子矩阵是否满足条件
到目前为止,这是我设法编写的代码。
其中:
char **readmat(int *n);
//从文件中读取矩阵,消除字符之间的空格
void print(char **mat,int n);
//打印存储的矩阵
int check(char **mat,int n);
//检查大小为n的矩阵的项是否满足数学运算符
int expand (char **mat,int n,int i);
//这应该是递归函数,一次获取一个元素并检查是否有任何条件要满足,如果是,则递增它
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **readmat(int *n);
void print(char **mat,int n);
int check(char **mat,int n);
int expand (char **mat,int n,int i);
int main(int argc, char *argv[])
{
char **mat;
int n, j;
mat=readmat(&n);
if(mat == NULL)
return 1;
if(check(mat,n)){
print(mat,n);
}
else if(expand(mat,n,0)==1){
print(mat,n);
}
else {
printf("Nessuna soluzione trovata.\n");
}
for(j=0; j<=n;j++)
free(mat[j]);
free(mat);
system("PAUSE");
return 0;
}
char **readmat(int *n){
FILE *fp;
char *line,nome[100];
int i,j,k;
char **mat;
printf("Inserire il nome del file: ");
scanf("%s",nome);
fp=fopen(nome,"r");
if(fp==NULL){
printf("Errore apertura file");
return NULL;
}
if(fgets(nome,100,fp)==NULL){
printf("Formato file non valido\n");
fclose(fp);
return NULL;
}
if(sscanf(nome,"%d",n)!=1){
printf("Errore nei parametri del file\n");
fclose(fp);
return NULL;
}
(*n)=(((*n)*2)-1);
mat=(char**)malloc((*n)*sizeof(char*));
for(i=0;i<=(*n);i++)
mat[i]=(char*)malloc((*n)*sizeof(char));
line=(char*)malloc(2*(*n)*sizeof(char));
i=0;
while(i<=2*(*n) && fgets(line,2*(*n)+2,fp)!=NULL){
j=0;
k=0;
while(j<=2*(*n)){
if(line[j]!=' '){
mat[i][k]=line[j];
k++;
}
j++;
}
i++;
}
return mat;
//print(mat, (*n));
}
void print(char **mat,int n){
int i=0,j=0;
for (i=0; i<n; i++) {
for (j=0; j<n; j++) {
printf("%c", mat[i][j]);
}
printf("\n");
}
}
int check(char **mat,int n) {
int i,j;
int k=1;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
if(mat[i][j]=='<'){
if(mat[i][j-1] >= mat[i][j+1])
k=0;
}
else if(mat[i][j]=='>'){
if(mat[i][j-1] <= mat[i][j+1])
k=0;
}
else if(mat[i][j]=='^'){
if(mat[i-1][j] >= mat[i+1][j])
k=0;
}
else if(mat[i][j]=='v'){
if(mat[i-1][j] <= mat[i+1][j])
k=0;
}
}
}
return k;
}
int expand (char **mat,int n,int i){
int j=i/n;
int k=i%n;
int p;
if(i>=n*n){
return 1;
}
else{
if((mat[j][k]>47)&&(mat[j][k]<58)){
if(mat[j][k]=='0'){
expand(mat,n,i+2);
}
for (p=(mat[j][k]-48); p<(10-(mat[j][k]-48)); p++) {
mat[j][k]=48+p;
if (check(mat,i)) {
if (expand(mat, n, i+2)) {
return 1;
}
}
}
i-=2;
mat[j][k]='0';
}
}
return 0;
}
示例的解决方案:正如您可以看到逻辑条件区域明显满足
0 | 0 | 1 | 0 | 0
- - - - v - - - -
1 > 0 | 0 | 0 | 3
- - - - - - - - -
0 | 0 < 2 | 0 | 0
- - - - v - - - -
0 | 1 | 0 | 0 | 4
^ - v - - - - - -
1 | 0 | 0 | 0 | 0
答案 0 :(得分:5)
存储矩阵的方式无关紧要。您可以随意存储它,只要您可以轻松获取/设置每个点的数值,并评估操作符是否满意。
非常广泛地说,您可以使用如下算法解决此类问题:
//returns true if this function solved the puzzle, false otherwise.
//gameData will be changed to the solved form of the puzzle if a solution exists, or remain unchanged if no solution exists.
//(so, whatever language you're using, ensure gameData is passed by reference here)
bool solve(gameData){
if (!isValid(gameData)){return false;} //oops, puzzle is unsolvable!
if (isComplete(gameData)){return true;} //puzzle is already solved; no further modification needed.
//choose a spot on the game board that hasn't been filled in yet.
int x;
int y;
getEmptySpot(gameData, &x, &y);
//iterate through all the possible values that could go into the empty spot.
//you don't need anything fancy here to generate legal values for i;
//if you accidentally supply an invalid value, then isValid()
//will notice in the next solve() call.
for (int i = 1; i <= 5; i++){
//try putting i in the empty spot.
setValue(gameData, x, y, i);
if (solve(gameData)){ //putting i in the spot led to a solution!
return true;
}
}
//didn't find a solution :(
//return gameData to its original state.
setValue(gameData, x, y, 0);
return false;
}
此算法执行强制递归搜索,尝试每个点的每个可能值,并在其进入非法状态时进行回溯。在超级最坏的情况下,它以指数时间运行,但实际上,开始时isValid()
调用会使任何明显不可行的分支短路,因此对于5x5输入它应该合理地快速完成。
isValid,isComplete,getEmptySpot和setValue的实现取决于你如何定义gameData。
isValid
应检查游戏数据是否处于非法状态 - 在您的情况下,应检查所有大于比较是否正确,并检查每个数字是否只出现一次每行和每列。这些检查应该忽略值为0的点,因为它们只是一个占位符,意思是“尚未填充”。
isComplete
应检查是否有任何地点没有“尚未填空”的占位符。 (isValid(gameData) && isComplete(gameData))
表示gameData已解决。
getEmptySpot
应找到尚未填写的地点。如果您担心速度,它应该找到一个可以合法输入的数字值最小的点。这将大大减少搜索树的宽度。
最后,setValue
应将给定的点设置为给定值。
答案 1 :(得分:0)
我会
矩阵示例:
0 0 0 0 0
0 0 0 0 3
0 0 2 0 0
0 0 0 0 4
0 0 0 0 0
--
1,3>2,3
2,1>2,2
3,2<3,3
3,3>4,3
4,1<5,1
4,2>5,2
--
启动规则后,意思很清楚(至少对我来说):
第1行第3列的值必须大于第2行第3列的值。
等
关于解算器,我将从以下开始:
当你完成前面的步骤后,你有一个部分(如果你很幸运的话)解决了矩阵,那么你必须编写一个核心函数来尝试每个组合,但考虑到动态规则(文件中的那些)和静态规则(制作游戏的规则)。