【问题标题】:Why isn't the code coming out of recursion?为什么代码不是递归出来的?
【发布时间】:2020-02-16 18:36:12
【问题描述】:

问题是找出一个单词在给定的 N x N 字母矩阵中出现的次数。我们可以从任何一个单元格移动到另一个相邻的单元格。第一行有一个整数 N,然后是一个 N x N 矩阵。下一行有 M(单词的大小),然后是要在矩阵中找到的字符串。

Input:
4
ABCD
ABCD
ABCD
ABCD
2
BC

Expected output:
10

我已经为此编写了以下代码,并使用递归来解决问题。函数 adj 使用它们的索引检查矩阵中的字符是否与前一个字符相邻。每当字符串完成时,函数检查都会增加计数。二维数组会检查已访问和未访问的元素。

我得到的输出为

OUPUT
1

编辑1:这个输出只是因为调试打印语句,所以if语句只被访问一次。这并不意味着在多次递归调用后计数变量为 1。

编辑 2:在 scanf 语句中不应该有 &。但输出仍然不是我们想要的。

编辑 3:

Another input
7
SHELDON
HSTYUPQ 
EHGXBAJ
LMNNQQI
DTYUIOP
OZXCVBN
NQWERTY
7
SHELDON

Expected output:
5

My output - 1

编辑 4(已解决!):所以问题在于写没有。网格矩阵的列数为 500,将其更改为 5 就可以了!感谢@gsamaras

代码

#include <stdio.h>

int vis[500][500], count;

int adj(int a, int b, int c, int d) {
    if((c == a - 1) && (d == b - 1)) {
        return 1;
    }
    else if((c == a - 1) && (d == b)) {
        return 1;
    }
    else if((c == a) && (d == b - 1)) {
        return 1;
    }
    else if((c == a - 1) && (d == b + 1)) {
        return 1;
    }
    else if((c == a + 1) && (d == b)) {
        return 1;
    }
    else if((c == a + 1) && (d == b + 1)) {
        return 1;
    }
    else if((c == a) && (d == b + 1)) {
        return 1;
    }
    else if((c == a + 1) && (d == b - 1)) {
        return 1;
    }
    else {
        return 0;
    }

}

void check(char grid[][500],int i, int j, int id, char word[], int n, int m) {
    if(id == m) {
        count++;
        printf("%d\n", count); // just to debug
    }
    else {
        for(int p = 0; p < n; p++) {
            for(int q = 0;q < n; q++) {
                if((grid[p][q] == word[id]) && (adj(i, j, p, q)) && (vis[p][q] != 1)) {
                    vis[p][q] = 1;
                    check(grid, p, q, id + 1, word, n, m);
                    vis[p][q] = 0;
                }
            }
        }
    }
}

int main() {
    int n, m, id = 0;
    char blank;
    scanf("%d", &n);
    scanf("%c", &blank);
    char grid[n][n+1];
    for(int i = 0; i < n; i++) {
        scanf("%s", grid[i]);
        grid[i][n] = '\0';
    }
    scanf("%d", &m);
    char word[m+1];
    scanf("%s", &word);

    for(int i = 0; i < n; i++) {
        for(int j = 0;j < n; j++) {
            if(grid[i][j] == word[id]) {
                vis[i][j] = 1;
                check(grid, i, j, id + 1, word, n, m);
                vis[i][j] = 0;
            }
        }
    }
    printf("%d\n", count);
    return 0;
}

【问题讨论】:

  • 正确的输出10怎么样?我快速扫了一眼,数了数 4。我错过了什么? ://
  • @gsamaras 你也可以对角数,对角线也是相邻的,所以还有 6 对也在那里
  • 所以任何元素最多可以有 8 个可能的相邻字符
  • @pmg 不,vis 是维护哪个元素已被访问,因为我们不能多次访问任何字符,然后我在递归调用后再次将其设置为 0,所以它很重要
  • @gsamaras:这里不是 DV'er,而是 DV 发生了。最好投票选出认为最合适的方式,然后继续前进。

标签: c arrays function recursion


【解决方案1】:

改变这个:

void check(char grid[][500], ......

到这里:

void check(char grid[][5], .......   // that should be equal to N + 1 (5 in your case)

由于您的网格大小为 N x N + 1。以 500 作为维度,您扭曲了网格,并且在尝试递归搜索它时,您不会遍历您期望的网格遍历..

如您所见,这并不灵活,因为N 可能会有所不同。您不能将grid 声明为全局的,因为它的尺寸不是固定的。应该改用Dynamic memory allocation


改变这个:

scanf("%s", &word);

到这里:

scanf("%s", word);

因为word 是一个字符数组。


动态内存分配的完整示例:

#include <stdio.h>
#include <stdlib.h>

int vis[500][500], count;

char **get(int N, int M) { /* Allocate the array */
    int i;
    char **p;
    p = malloc(N*sizeof(char *));
    for(i = 0 ; i < N ; i++)
        p[i] = malloc( M*sizeof(char) );
    return p;
}

void free2Darray(char** p, int N) {
    int i;
    for(i = 0 ; i < N ; i++)
        free(p[i]);
    free(p);
}

int adj(int a, int b, int c, int d) {
    // Same as in your question
}

void check(char** grid, int i, int j, int id, char word[], int n, int m) {
    if(id == m) {
        count++;
        printf("count = %d\n", count); // just to debug
    }
    else {
        for(int p = 0; p < n; p++) {
            for(int q = 0;q < 499; q++) {
              //printf("p = %d, q = %d, id = %d, grid[p][q] = %c, word[id] = %c\n", p, q, id, grid[p][q], word[id]);
                if((grid[p][q] == word[id]) && (adj(i, j, p, q)) && (vis[p][q] != 1)) {
                    vis[p][q] = 1;
                    check(grid, p, q, id + 1, word, n, m);
                    vis[p][q] = 0;
                }
            }
        }
    }
}

int main() {
    int n, m, id = 0;
    char blank;
    scanf("%d", &n);
    scanf("%c", &blank);
    char** grid = get(n, n + 1);
    for(int i = 0; i < n; i++) {
        scanf("%s", grid[i]);
        grid[i][n] = '\0';
    }
    scanf("%d", &m);
    char word[m+1];
    scanf("%s", word);

    for(int i = 0; i < n; i++) {
        for(int j = 0;j < n; j++) {
            //printf("i = %d, j = %d, id = %d\n", i, j, id);
            if(grid[i][j] == word[id]) {
                vis[i][j] = 1;
                check(grid, i, j, id + 1, word, n, m);
                vis[i][j] = 0;
            }
        }
    }
    printf("%d\n", count);

    free2Darray(grid, n);
    return 0;
}

输出(用于您的第一个输入):

count = 1
count = 2
count = 3
count = 4
count = 5
count = 6
count = 7
count = 8
count = 9
count = 10
10

PS:不是问题,只是关于可读性的建议:count 被初始化为 0,因为 it's a global variable,但最好在重要时显式初始化变量。

【讨论】:

  • 糟糕!更正了这一点(不是在原始问题中),现在输出是 1 2 2 下一行中的所有数字。所以还是不行
  • 感谢您的关注。哦耶!也更正了这个,(因为最后一个索引是 m-1 而不是 m),现在计数上升到 4 :)。但我认为这段代码也会掩盖对角线的情况..
  • @SukritKapil 我错了,应该是m。我发现了问题,检查更新的答案,现在有一个解决方案! :D
  • 正是@SukritKapil!我现在将更新我的答案。我正在尝试您的第二个输入(现在您已修复它),代码会产生正确的结果! :)
  • @Bhawan 在函数体中,看到了不同的grid,500 之一作为第二维,而不是N + 1。结果,当您尝试遍历它时,您会在许多单元格中看到它是空的(确切地说是垃圾值),因为所有网格现在都被视为具有 500 列的网格的第一行。将第二个 for 循环中的 n 更改为 499 以了解我的意思。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-18
  • 1970-01-01
  • 2014-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-14
相关资源
最近更新 更多