Futoshiki C рекурсивный решатель - PullRequest
2 голосов
/ 09 февраля 2012

Так что у меня есть эта программа, которая должна решить головоломку futoshiki в C который загружается из текстового файла с таким форматированием:

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

Ответы [ 2 ]

5 голосов
/ 09 февраля 2012

Способ хранения матрицы не должен иметь большого значения. Вы можете хранить его по своему усмотрению, при условии, что вы можете легко получить / установить числовое значение каждого спота и оценить, удовлетворены ли операторы.

Очень широко, вы можете решить проблемы этого типа, используя алгоритм, подобный этому:

//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 должен установить для данного места заданное значение.

0 голосов
/ 09 февраля 2012

Я бы

  1. удалил размер матрицы.это очевидно, если прочитать саму матрицу
  2. удалить каналы и другие символы, оставив только пробелы
  3. добавить операторы после матрицы в специальном «кодированном» формате
  4. aодна функция могла бы взять правила и попытаться решить матрицу

пример матрицы:

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.

и т. д.

Что касается решателя, я бы начал следующим образом:

  1. поиск в матрице, если есть правило, включающее ячейку с 2, которая должна быть больше, чем другая ячейка.Если да, вы можете сразу вставить 1 в другую ячейку
  2. , повторить точку 1 для всей матрицы, так что вы получите новую, частично решенную матрицу в качестве отправной точки
  3. То жевещь как и выше с 4 с правилом «меньше чем».Вы можете поместить 5 в соответствующую ячейку
  4. Теперь ищите, есть ли строка (или столбец) с заполненными 4 числами.Если это так, то 5-е число очевидно.

Когда вы выполнили предыдущие шаги, у вас есть частично (возможно, полностью, если вам повезет) решенная матрица, тогда вы должны написать основную функцию, котораяпробует каждую комбинацию, но учитывает динамические правила (те, что в файле) и статические правила (те, которые делают игру).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...