【问题标题】:What could be the reason behind SIGABRT error for SPOJ WATER problem? [duplicate]SPOJ WATER 问题的 SIGABRT 错误背后的原因可能是什么? [复制]
【发布时间】:2021-01-24 21:19:51
【问题描述】:

SPOJ WATER Problem 下面的代码在 ideone、glot 和本地运行良好,但在提交解决方案时会出现 SIBABRT 运行时错误。

我的解决方案虽然没有优化,但大致遵循以下算法

  1. 根据最低级别/高度对图表进行排序。
  2. 遍历已排序的图,并逐个到达最小节点并执行 3 和 4。
  3. 用最小围墙的值填充节点
  4. FloodFill:用最少的围墙填充新级别/高度的整个表面(多个节点)3。
  5. 如果超出区域或发现任何较低的表面,则中止填海。

我生成了多个数据集,并与其他已接受的解决方案交叉检查了结果,它似乎产生了正确的结果,但由于此错误,我无法提交。

请帮助我了解其背后的原因。 提前致谢!

#include <iostream>
#include<queue>
#include<stack>
#include<string>
#include<climits>
#include<algorithm>
#include<sstream>

using namespace std;


void convertStringToVector(vector<int>& v, string& data, char delim =  ' '){
    stringstream ss(data);
    string numstr;
    while(getline(ss, numstr, delim )){
        v.push_back(stoi(numstr));
    }
}

typedef struct Node{
    int value;
    bool visited;
    int pos;
    Node(int val, int pos, bool isvisited = false){
        this->value = val;
        
        this->pos = pos;
        this->visited = isvisited;
    }
}Node;



typedef struct Tank{
    int level;
    Tank(int capacity = 0){
        this->level = capacity;
    }
}Tank;

void fillSpot(int index,int level, vector<Node>& graph, vector<Node>& ograph, Tank& tank, int rmax, int cmax){
    int pos = graph[index].pos;
    vector<int> rr = {1,-1,0,0};
    vector<int> cc = {0,0,1,-1};
    Node& currentNode = ograph[pos];
    int x = int(pos / cmax);
    int y = pos % cmax;
    int min = INT_MAX;
    int currentLevel = currentNode.value;
    for(int i = 0; i< rr.size(); i++){
        int newx = x + rr[i];
        int newy = y + cc[i];
        
        int newpos = (newx * cmax) + newy;
        if(newx <0 || newy < 0 || newx >=rmax || newy>=cmax){
            return;
        }
        
        int neighbour_level = ograph[newpos].value;
        if(neighbour_level < level || neighbour_level == currentLevel){
            return;
        }
        
        if(neighbour_level > level && neighbour_level < min){
            min = neighbour_level;
        }
        
    }
    if(min < INT_MAX && min > currentLevel ){
        
        tank.level = tank.level + (min - currentNode.value);
        currentNode.value = min;  
    }
};

int explore_neighbours(int currNodePos, vector<Node>& graph, vector<Node>& ograph, Tank& tank, int rmax, int cmax, queue<int>& que, int surfaceHeight){
    Node& currNode = ograph[currNodePos];
    int level = currNode.value;
    int pos = currNode.pos;
    vector<int> rr = {1,-1,0,0};
    vector<int> cc = {0,0,1,-1};
   
    int x = int(pos / cmax);
    int y = pos % cmax;
    int min = INT_MAX;
    for(int i = 0; i< rr.size(); i++){
        int newx = x + rr[i];
        int newy = y + cc[i];
        
        int newpos = (newx * cmax) + newy;
        if(newx <0 || newy < 0 || newx >=rmax || newy>=cmax){
            return -1;
        }
        
        Node& neighbourNode = ograph[newpos];
        int neighbour_level = ograph[newpos].value;
  
      
        if(neighbour_level < surfaceHeight){
            return -1;
        }
       
        if(neighbour_level == level && !neighbourNode.visited){
            neighbourNode.visited = true;
            que.push(neighbourNode.pos);
            
        }
        if(neighbour_level > surfaceHeight && neighbour_level < min && !neighbourNode.visited){
            min = neighbour_level;
        }
        
    }
    return min;
    
};

void fillSurface(int index, vector<Node>& graph, vector<Node>& ograph, Tank& tank, int rmax, int cmax){
    int pos = graph[index].pos;
    queue<int> que;
    stack<int> stk;
  
    const int LOWER_HEIGHT_FOUND = -1;
    int minSurfaceLevel = INT_MAX;
    bool abrupt_break = false;
    
    Node& currentNode = ograph[pos];
    que.push(currentNode.pos);
 
    int currentLevel = currentNode.value;
    while(!que.empty()){
        int currNodePos = que.front();
        que.pop();
        Node& currNode = ograph[currNodePos];
        stk.push(currNodePos);
        currNode.visited = true;
        int newMinSurfaceLevel = explore_neighbours(currNodePos, graph, ograph, tank, rmax, cmax, que, currentLevel);
        if(newMinSurfaceLevel == LOWER_HEIGHT_FOUND){
            abrupt_break = true;
            break;
        }
        
        if(newMinSurfaceLevel > currentLevel && newMinSurfaceLevel < minSurfaceLevel){
            minSurfaceLevel = newMinSurfaceLevel;
        }
    }
    if(abrupt_break){
        while(!que.empty()){
            Node & n = ograph[que.front()];
            que.pop();
            n.visited = false;
        }
    }
    while(!stk.empty()){
        int nodePos = stk.top();
        stk.pop();
        Node& n = ograph[nodePos];
        if(abrupt_break){
            n.visited = false;
        }else if(minSurfaceLevel < INT_MAX){
            tank.level = tank.level + (minSurfaceLevel - currentLevel);
            n.value = minSurfaceLevel;
            
        }
        n.visited = false;
    }
}

void buildGraph(){
    string testcases;
    getline(cin, testcases);
    int testcase = 0;
    while(testcase < stoi(testcases)){
        vector<Node> graph, ograph;
        Tank tank = Tank();
        string dims;
        getline(cin, dims);
        vector<int> dimensions;
        convertStringToVector(dimensions, dims);
        
        int rmax = dimensions[0];
        int cmax = dimensions[1];
        
        for (int i =0 ; i < rmax; i++){
            string row;
            getline(cin, row);
            vector<int> rowdata;
            convertStringToVector(rowdata, row, ' ');
            for(int j= 0; j < cmax; j++){
                int pos = i * cmax + j;
                int val = rowdata[j];
                Node gn = Node(val, pos, false);
                Node ogn = Node(val, pos, false);
                graph.push_back(gn);
                ograph.push_back(ogn);
            }
        }
        
        //sort the graph based on value
        sort(graph.begin(), graph.end(), [](Node const& n1, Node const& n2)->bool{
            return n1.value < n2.value;
        });
        

        for(int i = 0; i < graph.size(); i++){
            Node leastfilledNode = graph[i];
            int position = leastfilledNode.pos;
            int level = leastfilledNode.value;
            fillSpot(i, level, graph, ograph, tank,  rmax, cmax);
            fillSurface(i, graph, ograph, tank,  rmax, cmax);
        }

        cout<<tank.level<<endl;
        
        testcase++;
    }
}

int main() {
    buildGraph();
    return 0;
}

【问题讨论】:

  • 我生成了多个数据集 -- 停止自己生成数据集并遵循指南here
  • 所以你问的是一个你甚至不能直接访问的系统上的问题。这通常不会提出好的问题。无论如何,你知道SIGABRT是由什么引起的吗?您的代码的哪些部分可能导致这种情况?
  • 为什么您认为需要将整数数据作为字符串输入?
  • 我建议您将数据读取为整数。添加读取字符串的代码,然后尝试解析字符串以获取整数数据,这很可能会导致您在输入例程中出错。

标签: c++ algorithm graph breadth-first-search


【解决方案1】:
        vector<Node> graph, ograph;
        Tank tank = Tank();
        string dims;
        getline(cin, dims);
        vector<int> dimensions;
        convertStringToVector(dimensions, dims);
        
        int rmax = dimensions[0];
        int cmax = dimensions[1];

没有看到输入,很难知道出了什么问题,但我看到了一些你可以提防的早期机会。

如果getline(cin, dims);之后字符串为空,或者数字太小怎么办? dimensions 最初是空的,您在任何时候都不会验证它的大小。当您使用dimensions 的前两个元素时,如果它们不存在,您肯定会招来麻烦。

我会检查类似的东西,以确保尺寸符合您的期望。如果输入不正确,则抛出std::runtime_error

一种快速的方法是使用检查向量访问:

    int rmax = dimensions.at(0);
    int cmax = dimensions.at(1);

您可能知道,vector::at 会根据 vector::size 检查其参数,而 vector::operator[] 不会。

查看其余代码,我没有注意到对失败或前提条件断言的单一检查。它隐含地假设一切都按计划进行。 SIGABRT 告诉你这个假设是不正确的。

【讨论】:

    猜你喜欢
    • 2021-11-01
    • 1970-01-01
    • 2013-06-25
    • 2011-11-18
    • 2014-10-08
    • 2022-07-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-20
    相关资源
    最近更新 更多