为什么我的逻辑在SPOJ TOPOSORT上无法正常工作?

时间:2013-06-26 11:17:41

标签: algorithm graph depth-first-search topological-sort

给出的问题是http://www.spoj.com/problems/TOPOSORT/ 输出格式特别重要:

Print "Sandro fails." if Sandro cannot complete all his duties on the list. 
If there is a solution print the correct ordering, 
the jobs to be done separated by a whitespace. 
If there are multiple solutions print the one, whose first number is smallest, 
if there are still multiple solutions, print the one whose second number is smallest, and so on. 

我正在做的只是通过反转边来做dfs,即如果作业A在作业B之前完成,则存在从B到A的有向边。我通过对我创建的邻接列表进行排序并分别存储没有任何约束的节点来维护顺序,以便稍后以正确的顺序打印它们。使用了两个标志数组,一个用于标记已发现的节点,另一个用于标记已探查所有邻居的节点。

现在我的解决方案是http://www.ideone.com/QCUmKY(重要的功能是访问功能)并且在运行正确的10个案例后给出了WA因此很难弄清楚我在哪里做错了因为它运行所有的我手工完成的测试用例。

3 个答案:

答案 0 :(得分:5)

我认为这里的问题是DFS拓扑排序算法只能保证产生有效的拓扑排序,而不是按字典顺序排列第一拓扑排序(这就是你需要的)。

您可以解决此问题的一种方法是更改​​您用于执行拓扑排序的算法。而不是使用DFS,请考虑使用其他标准算法,该算法通过维护一组具有indegree 0的所有节点,然后重复删除一个并更新具有indegree 0的节点集来工作。如果使用优先级队列来选择具有indecree 0并且在每次迭代时具有最低数值,您将返回满足问题给出的约束的拓扑排序。

希望这有帮助!

答案 1 :(得分:4)

以下是一个打破程序的输入:

4 4
2 4
4 1
3 1

答案应该是2 3 4 1,但你的代码打印3 2 4 1。

原因是您以索引顺序访问顶点;但是,更高阶的索引可能会导致低索引节点。

这个问题应该有一个简单的O(m + nlogn)解决方案,但我看不出如何轻松修复你的代码。自从你写完以来,你知道这段代码是最好的,所以祝你好运。

答案 2 :(得分:2)

dfs算法在这个特定问题中超时。通过一些巧妙的技巧,您可以获得O(m)解决方案的复杂性。您需要消除用于按顺序对所有边进行排序的排序。我保留了一个反向边缘列表,即对于两个边缘u-> v和w-> v,我最初将它们添加到列表li [v] - > u-> w中。然后我从1到n遍历,我创建了修正的有向边,但这次它们会自动按顺序出现。

无论如何这次出来了(对我来说是测试用例12)。你需要一个非常优化的算法。算法templatetypedef提及工作正常,可能dfs算法中dfs的递归开销有点过多。

这个想法很简单,你可以在这里阅读http://en.wikipedia.org/wiki/Topological_sorting

基本上,您可以使用零indegree完成任务,一旦任务完成,您将删除所有传出边并更新所有indegree并找到零indegree的另一个任务。为了使事情井然有序,您可以使用优先级队列。

#include <iostream>
#include <vector>
#include <queue>

using namespace std;
int indeg[10005];
int topo[10005];
vector <int> g[10005];
int main(){
        int n,m;
        int cur= 0;
        cin >> n >> m;
        for (int i = 0; i < m; i++){
                int x,y;
                scanf("%d %d" ,&x, &y);
                indeg[y]++;
                g[x].push_back(y);
        }
        priority_queue <int> q;
        for(int i = 1; i <= n; i++)
                if (!indeg[i]) q.push(-1*i);
        while(!q.empty()){
                int nd = -1 * q.top();
                q.pop();
                for(int i = 0; i < g[nd].size(); i++){
                        indeg[g[nd][i]]--;
                        if (!indeg[g[nd][i]])
                                q.push(-1*g[nd][i]);
                }
                topo[cur++] = nd;
        }
        if (cur!= n){
                cout << "Sandro fails." << endl;
                return 0;
        }

        for(int i = 0; i < n-1; i++)
                printf("%d ", topo[i]);
        printf("%d\n", topo[n-1]);


        return 0;
}