DFS在求解海岸线长度方面的问题

Trouble with DFS in solving coastline length

本文关键字:方面 问题 海岸线 DFS      更新时间:2023-10-16

我想解决一个问题,这是我在网站https://open.kattis.com/problems/coast上发现的。问题的版本是,对于给定的景观地图,我应该打印出海岸线的长度(不包括内岛)。

我的想法是,通过添加额外的层来解决这个问题,然后启动DFS,这样算法将遍历地图中的每个可能的瓷砖,然后观察每个瓷砖,瓷砖周围有多少边框。

然而,对于特定的输入,是我的算法不工作。当我在这个网站(open.kattis)上提交解决方案时,它说,我的程序在26次测试中的第9次给出了错误的答案(之前的8次测试是ok的),但没有任何进一步的解释。

谁能看看我的程序,然后对我说,为什么它不好?我哪里出错了?由于

#include <iostream>
#include <stack>
#include <sstream>
using namespace std;
int main() {
    string line;
    getline(cin, line);
    int rows = 0;
    int columns = 0;
    stringstream stream(line);
    stream >> rows;
    stream >> columns;
    int map[rows][columns];
    for (int i = 0; i < rows; i++) {
        getline(cin, line);
        for (int j = 0; j < columns; j++) {
            map[i][j] = line[j] - 48;
        }
    }
    //parsed landscape into 2d array
//    int rows = 5;
//    int columns = 6;
//    int map[rows][columns] = {
//            {0, 1, 1, 1, 1, 0,},
//            {0, 1, 0, 1, 1, 0,},
//            {1, 1, 1, 0, 0, 0,},
//            {0, 0, 0, 0, 1, 0,},
//            {0, 0, 0, 0, 0, 0,},
//    };
int bigMap[rows+2][columns+2];
bool visited[rows+2][columns+2];
//create bigger map, so DFS can start from corner and assume
//that there is water around everywhere
//also initialize array visited for DFS
//add 2 new rows, before and after existing one
for (int i = 0; i < columns+2; i++) {
    bigMap[0][i] = 0;
    bigMap[rows + 1][i] = 0;
    visited[0][i] = false;
    visited[rows + 1][i] = false;
}
//add 2 new columns, before and after existing
//copy original map to new one
for (int i = 0; i < rows; i++) {
    bigMap[i+1][0] = 0;
    bigMap[i+1][columns + 1] = 0;
    visited[i+1][0] = false;
    visited[i+1][columns + 1] = false;
    for (int j = 0; j < columns; j++) {
        bigMap[i+1][j+1] = map[i][j];
        visited[i+1][j+1] = false;
    }
}
rows += 2;
columns += 2;
//starting DFS
int x = 0, y = 0;
//visited[x][y] = true; <-- edit
pair <int, int> coordinates;
coordinates.first = x;
coordinates.second = y;
stack<pair <int, int> > st;
//first vertex in stack
st.push(coordinates);
//total sum of borders
int borders = 0;
while(!st.empty()) {
    //check coordinates in each round
    x = st.top().first;
    y = st.top().second;
    //navigate to new vertex (only if new vertex wasn't visited (visited[x][y] == 0) and only
    //if there is water (bigMap[x][y] == 0) and check if new vertex is still in the map
    //if there is no possible vertex, then we reached the end so then pop the vertex and
    //look in another way
    if (visited[x][y+1] == 0 && bigMap[x][y+1] == 0 && y + 1 < columns) {
        y++;
        coordinates.second = y;
        st.push(coordinates);
    } else {
        if (visited[x+1][y] == 0 && bigMap[x+1][y] == 0 && x + 1 < rows) {
            x++;
            coordinates.first = x;
            st.push(coordinates);
        } else {
            if (visited[x][y-1] == 0 && bigMap[x][y-1] == 0 && y > 0) {
                y--;
                coordinates.second = y;
                st.push(coordinates);
            } else {
                if (visited[x-1][y] == 0 && bigMap[x-1][y] == 0 && x > 0) {
                    x--;
                    coordinates.first = x;
                    st.push(coordinates);
                } else {
                    st.pop();
                    continue;
                }
            }
        }
    }
    //visited new vertex, so look around him and count borders
    visited[x][y] = true;
    if (bigMap[x][y+1] == 1 && y + 1 < columns) borders++;
    if (bigMap[x+1][y] == 1 && x + 1< rows) borders++;
    if (bigMap[x][y-1] == 1 && y > 0) borders++;
    if (bigMap[x-1][y] == 1 && x > 0) borders++;
}
cout << borders << endl;
return 0;

问题是您每次都在循环中重用变量coordinates,而没有将其设置为正确的值。您的if测试级联假设coordinates被设置为当前位置。只有当你在dfs中下降时,这才是正确的。一旦您再次开始上升,coordinate将指向错误的位置。

简单的解决方案,添加

    coordinates = st.top();

在循环的顶端

这是一个示例地图,它目前会出错。

5 6
000000
011100
001010
000100
000000

答案应该是14,但目前你得到的是18,因为程序到达了第三行,第四列的湖。

要检查它是否这样做,在循环的末尾添加一个调试行,它在这里添加边框。

cout << "adding " << x << " " << y << "n"; 

然后您可以验证程序是否考虑了它不应该考虑的位置。

我认为它将会失败为{1,0,0,0},{0,1,1,0},{0,1,1,0},{0,0,0,0}。这是因为顶点0,0设置了visited=true,从而阻止了遍历的完成。将其设为false为0,0应该会改善情况。