对于SPOJ WATER问题,SIGABRT错误背后的原因可能是什么?

问题描述

我下面的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};
    vector<int> cc = {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,int cmax,queue<int>& que,int surfaceHeight){
    Node& currNode = ograph[currNodePos];
    int level = currNode.value;
    int pos = currNode.pos;
    vector<int> rr = {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,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,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,cmax);
            fillSurface(i,cmax);
        }

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

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

解决方法

        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的前2个元素时,肯定会遇到麻烦。

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

一种快速的方法是使用选中的向量访问权限:

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

您可能知道,vector::at针对vector::size检查其参数,而vector::operator[]则不检查。

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