简体   繁体   English

最长路径:C语言中带约束的递归回溯

[英]Longest Path: Recursive Backtracking with Constraints in C

I was recently assigned a problem, which boils down to finding the longest path in a given matrix, where two cells are adjacent iff the neighboring value is less than the present cell. 最近给我分配了一个问题,归结为找到给定矩阵中最长的路径,其中两个单元格相邻,如果相邻值小于当前单元格。 I've been tearing my hair out trying to figure it out, so I would be extremely grateful for any help. 我一直在努力寻找解决方案的方法,因此我将非常感谢您的帮助。 However, as I said, this is a homework assignment, so suggestions and hints are very welcome (but try not to make it too easy for me). 但是,正如我所说,这是一项家庭作业,因此非常欢迎您提出建议和提示(但请不要对我来说太简单了)。

Here's the latest version of my code: 这是我的代码的最新版本:

#include <stdio.h>

int isValid(int i, int j, int rows, int cols) {
    if (i < 0 || i >= rows || j < 0 || j >= cols)
        return 0;
    return 1;
}

void printpath(int path[1000][2]) {
    int i = 0;
    while (path[i][0] != -1) {
        printf("(%d, %d) ", path[i][0], path[i][1]);
        i++;
    }
}

void print_array_path(int path[1000][2], int array[100][100]) {
    int i = 0;
    while (path[i][0] != -1) {
        printf("%d -> ", array[path[i][0]][path[i][1]]);
        i++;
    }
}

int path_length(int path[1000][2]) {
    int i = 0, s = 0;
    while ( path[i][0] != -1) {
        s++;
        i++;
    }
    return s-1;
}
void add_path(int path[1000][2], int u, int v) {
    int i = 0;
    while (path[i][0] != -1) {
        i++;
    }
    path[i][0] = u; // row
    path[i][1] = v; // column
}
int last_i(int path[1000][2], int s) {
    int v;
    v = path[s][0];
    //path[i-2][0] = -1;
    return v;
}
int last_j(int path[1000][2], int s) {
    int u;
    u = path[s][1];
    //path[i-2][1] = -1;
    return u;
}

int c1[4] = {1, 0, -1, 0};
int c2[4] = {0, 1, 0, -1};
int dfs(int visited[100][100], int array[100][100], int i, int j, int rows, int cols, int path[1000][2], int length) {
    // 1. Take the current visited, along with the previous vertex, to create a unique
    // list of visited vertices.
    // 2. For every direction, check if it is valid. If valid, do dfs(visited, current, choice)
    // 3. If all four directions are checked, with no valid choice, report the solution.
    int s;

    for (s=0; s<4; s++) {
        if ( isValid(i+c1[s], j+c2[s], rows, cols) && !(visited[i+c1[s]][j+c2[s]]) && (array[i][j] < array[i+c1[s]][j+c2[s]]) ) {
            // TODO visited.add(current)
            visited[i][j] = 1;
            add_path(path, i+c1[s], j+c2[s]);
            //printf("%d -> ", array[i+c1[s]][j+c2[s]]);
            //printpath(path);
            length += 1;
            dfs( visited, array, i+c1[s], j+c2[s], rows, cols, path, length);
        } else if (s==3) {
            //visited[i+c1[s]][j+c2[s]] = 0;
            //printf("end at %d, %d\n", i, j);
            if ( (last_i(path, i) == i) && (last_i(path, j) == j) ){
                printf("%d ", length);
                print_array_path(path, array);
                printf("\n");
                continue;
            }
            length -= 1;
            dfs(visited, array, last_i(path, i-1), last_j(path, i-1), rows, cols, path, length);
            return path[i][0];
        }
    }
}


int main() {
    int array[100][100];
    int rows, columns;
    scanf("%d", &rows);
    scanf("%d", &columns);

    int i, j;
    for (i = 0; i < rows; i++) {
        for (j = 0; j < columns; j++) {
            scanf("%d", &array[i][j]);
        }
    }

    for (i = 0; i < rows; i++) {
        for (j = 0; j < columns; j++) {
            printf("%d ", array[i][j]);
        }
        printf("\n");
    }
    int visited[100][100];
    for (i=0; i<rows; i++) {
        for (j=0; j<columns; j++) {
            visited[i][j] = 0;
        }
    }
    int path[1000][2];
    for (i=0; i<1000; i++) {
        for (j=0; j<2; j++) {
            path[i][j] = -1;
        }
    }
    path[0][1] = 0;
    path[0][0] = 0;
    int length = 0;
    dfs(visited, array, 0, 0, rows, columns, path, length);

}

Basically, it first collects an inputted matrix, and starts at the first cell (once I get the whole thing working, it would move through every cell), calls a search function, checks to see if a neighboring cell is valid, then calls the search again. 基本上,它首先收集输入的矩阵,并从第一个单元格开始(一旦我使整个事情正常工作,它将遍历每个单元格),调用搜索函数,检查相邻单元格是否有效,然后调用再次搜索。 If all four directions have been checked, it backtracks. 如果所有四个方向均已检查,则它将回溯。 The current path is tracking in a list path . 当前路径正在跟踪列表path My problem seems to mostly be in the backtracking part. 我的问题似乎主要在回溯部分。 However, I'm not sure how to move forward. 但是,我不确定如何前进。 This code barely compiles at the moment, as I've been trying so many different things. 由于我尝试了许多不同的事情,此代码目前无法编译。 At this point, I'd like to catch my breath and really understand what I'm trying to do. 在这一点上,我想屏住呼吸,并真正了解我要做什么。

Earlier on, I tried generating an adjacency list, and constructing paths from that, but the backtracking option seemed more promising. 早些时候,我尝试生成一个邻接列表,并从中构造路径,但是回溯选项似乎更有希望。 A typical input looks like this: 典型的输入如下所示:

5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9

To express a 5x5 matrix. 表达5x5矩阵。 The expected output would be 25 (25->24-> ... 2->1). 预期输出为25(25-> 24-> ... 2-> 1)。 Please let me know if any other info would be helpful. 请让我知道其他信息是否有帮助。 Any advice / tips would be greatly appreciated! 任何建议/提示将不胜感激! Thanks. 谢谢。

EDIT: The original problem was reversed (ie two cells are adj iff the neighbor has a strictly lower value. The two problems are equivalent, right?) 编辑:原来的问题是相反的(即两个单元格相邻的邻居具有严格较低的值。两个问题是等效的,对吧?)

EDIT 2: I made some changes to the code, and I think I'm a bit closer. 编辑2:我对代码进行了一些更改,我想我有点接近。 It now gives this output: 现在给出以下输出:

3 1 -> 16 -> 17 -> 24 -> 25 -> 
3 1 -> 16 -> 17 -> 24 -> 25 -> 
4 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 
9 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 
10 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 
8 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 
17 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 
20 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 
21 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 
21 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 
19 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
19 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
13 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
12 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
11 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
9 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
8 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
7 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
8 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
7 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
5 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
4 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
2 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 
1 1 -> 16 -> 17 -> 24 -> 25 -> 18 -> 25 -> 19 -> 20 -> 21 -> 22 -> 25 -> 23 -> 25 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 23 -> 13 -> 14 -> 23 -> 15 -> 25 -> 

I replaced the above code to reflect those changes. 我替换了上面的代码以反映这些更改。 It seems very close, but not quite the right answer, namely, the path seems to be found but the lengths are not correct. 看起来很接近,但是答案不是很正确,也就是说,虽然找到了路径,但是长度不正确。

The main problem of the current code is trackback. 当前代码的主要问题是引用。
It is necessary to return the environment after executing the function. 执行功能后必须返回环境。
Specific modification example: 具体修改示例:

#include <stdio.h>
#include <stdbool.h>

#define MAX_LEN 1000
#define SIZE     100
#define EOP -1 //End Of Path

typedef struct pos {
    int r, c;//rows, columns
} Pos;

Pos EPOS = { EOP, EOP};

bool isValidPos(Pos pos, int rows, int cols) {
    return  0 <= pos.r && pos.r < rows && 0 <= pos.c && pos.c < cols;
}

bool isVisited(Pos pos, bool visited[SIZE][SIZE]){
    return visited[pos.r][pos.c];
}
/* unused
void printPos(Pos pos){
    printf("(%d, %d)", pos.r, pos.c);
}
void printpath(Pos path[]){
    while(path->r != EOP)
        printPos(*path++);
}
int path_length(Pos path[]) {
    int i = 0;
    while((path++)->r != EOP)
        ++i;
    return i;
}
void add_path(Pos path[], Pos pos) {
    while (path->r != EOP)
        ++path;
    *path = pos;
    path[1] = EPOS;
}
*/
int valueOf(Pos pos, int array[SIZE][SIZE]){
    return array[pos.r][pos.c];
}

void print_path(Pos path[], int array[SIZE][SIZE]){
    while(path->r != EOP)
        printf("%d -> ", valueOf(*path++, array));
}

const Pos rpos[] = {{1,0},{0,1},{-1,0},{0,-1}};//relative position

void dfs(bool visited[SIZE][SIZE], int array[SIZE][SIZE], Pos pos, int rows, int cols, Pos path[], int length){
    visited[pos.r][pos.c] = true;
    int value = valueOf(pos, array);
    bool CantAddPath = true;

    for (int s = 0; s < sizeof(rpos)/sizeof(*rpos); s++){
        Pos movePos = { .r = pos.r + rpos[s].r, .c = pos.c + rpos[s].c};
        if(!isValidPos(movePos, rows, cols) || isVisited(movePos, visited) || value >= valueOf(movePos, array))
            continue;

        CantAddPath = false;
        path[length++] = pos;//add_path(path, pos);length++;
        dfs(visited, array, movePos, rows, cols, path, length);
        path[--length] = EPOS;
    }
    if(CantAddPath){
        printf("%d ", length+1);//+1: current (last) postion
        print_path(path, array);
         printf("%d\n", value);//value of current (last) position
    }
    visited[pos.r][pos.c] = false;
}

int main(void) {
    int array[SIZE][SIZE];
    int rows, columns;
    scanf("%d", &rows);
    scanf("%d", &columns);

    int i, j;
    for(i = 0; i < rows; i++)
        for(j = 0; j < columns; j++)
            scanf("%d", &array[i][j]);

    for(i = 0; i < rows; i++){
        for(j = 0; j < columns; j++)
            printf("%2d ", array[i][j]);
        printf("\n");
    }
    bool visited[SIZE][SIZE] = {{ false }};

    Pos path[MAX_LEN];
    for (i = 0; i < MAX_LEN; i++){
        path[i] = EPOS;
    }

    Pos start = { 0, 0 };
    //path[0] = start;//Mismatch with `int length = 0;`
    int length = 0;
    dfs(visited, array, start, rows, columns, path, length);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM