用于spoj的底部的Kosaraju算法

时间:2014-03-28 18:23:55

标签: c++ algorithm

我正在尝试解决http://www.spoj.com/problems/BOTTOM/

以下是我要遵循的步骤:

1)使用Kosaraju算法找到强连通分量。 2)考虑一个强连接的组件。考虑一下优势。现在考虑从u到某个顶点的所有边v。如果v位于某个其他SCC中,则消除整个强连通分量。否则包括解决方案中的所有元素。

然而,我经常得到西澳大利亚州。请帮忙。

这是我的代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <fstream>
#include <iterator>
#include <queue>
using namespace std;
int k = 0;
int V, E;
bool fix[5001];
bool fix2[5001];
int compNum[5001];

void dfs(int v, vector< vector<int> >&G, bool *fix, vector <int> &out) {
    fix[v] = true;
    for (int i = 0; i < G[v].size(); i++) {
        int u = G[v][i];
        if (!fix[u]) {
            fix[u] = true;
            dfs(u, G, fix, out);
        }
    }
    out.push_back(v);
}

void dfs2(int v, vector< vector<int> >&G, bool *fix2, vector < vector<int> > &components) {
    fix2[v] = true;
    for (int i = 0; i < G[v].size(); i++) {
        int u = G[v][i];
        if (!fix2[u]) {
            fix2[u] = true;
            dfs2(u, G, fix2, components);
        }
    }
    components[k].push_back(v);
    compNum[v] = k;
}

int main() {
    int a, b;

    while (true) {

        cin >> V; if (V == 0) break; cin >> E;
        vector< vector<int> >G(V + 1);
        vector< vector<int> >G2(V + 1);

        vector<int>out;
        vector < vector<int> >components(V + 1);


        for (int i = 0; i < E; i++) {
            cin >> a >> b;
            G[a].push_back(b);
            G2[b].push_back(a);
        }



        for (int i = 1; i <= V; i++) {
            if (!fix[i])
                dfs(i, G, fix, out);
        }

        reverse(out.begin(), out.end());

        for (int i = 0; i < out.size(); i++){
            if (!fix2[out[i]]) {
                dfs2(out[i], G2, fix2, components);
                k++;
            }
        }

        vector<int>gamotana;

        for (int i = 0; i < components.size(); i++) {
            for (int j = 0; j < components[i].size(); j++) {
                bool check = true;
                for (int z = 0; z < G[components[i][j]].size(); z++)
                {
                    if (compNum[G[components[i][j]][z]] != i)
                    {
                        check = false; goto next123;
                    }
                }
                if (check)
                    gamotana.push_back(components[i][j]);
            }
        next123:;
        }

            sort(gamotana.begin(), gamotana.end());

        for (int i = 0; i < gamotana.size(); i++)
            cout << gamotana[i] << " ";

        for (int i = 0; i < 5001; i++) {
            fix[i] = false;
            fix2[i] = false;
            compNum[i] = -1;
        }
        k = 0;

        cout << endl;
    }

    return 0;

}

2 个答案:

答案 0 :(得分:1)

在您的算法描述中,您说如果某些边缘通向不同的组件,则会消除整个连接的组件。

但是,在您的代码中,您似乎将组件i中的所有顶点j添加到解决方案中,直到找到边缘。换句话说,即使组件不是接收器,您仍可能错误地将某些顶点报告为接收器。

我想你应该做更多这样的事情:

    for (int i = 0; i < components.size(); i++) {
        for (int j = 0; j < components[i].size(); j++) {

            for (int z = 0; z < G[components[i][j]].size(); z++)
            {
                if (compNum[G[components[i][j]][z]] != i)
                {
                    goto next123;
                }
            }
        }

        for (int j = 0; j < components[i].size(); j++)
            gamotana.push_back(components[i][j]);

    next123:;
    }

当然,可能会有更多问题。我建议你先尝试构建和测试一些小例子,然后测试一个强力求解器来识别失败的案例。

答案 1 :(得分:0)

#include<bits/stdc++.h>
using namespace std;

void dfs(vector<int>* edges, stack<int>& finishedVertices, bool* visited, int n, int start){
    visited[start] = true;
    for(int i = 0 ; i < edges[start].size() ; i++){
        int node = edges[start][i];
        if(!visited[node]){
            dfs(edges, finishedVertices, visited, n, node);
        }
    }
    finishedVertices.push(start);
}

void dfs_reverse(vector<int>* edgesT, bool* visited, unordered_map<int,vector<int>>& SCC, int node, int k){
    SCC[k].push_back(node);
    visited[node] = true;

    for(int i = 0 ; i < edgesT[node].size() ; i++){
        int new_node = edgesT[node][i];
        if(!visited[new_node]){
            dfs_reverse(edgesT, visited, SCC, new_node, k);
        }
    }
}

void getSCC(vector<int>* edges, vector<int>* edgesT, int n){
    bool* visited = new bool[n];
    for(int i = 0 ; i < n ; i++){
        visited[i] = false;
    }

    stack<int> finishedVertices;
    for(int i = 0 ; i < n ; i++){
        if(!visited[i]){
            dfs(edges, finishedVertices, visited, n, i);
        }
    }

    unordered_map<int,vector<int>> SCC;
    int k = 0;

    for(int i = 0 ; i < n ; i++){
        visited[i] = false;
    }

    while(!finishedVertices.empty()){
        int node = finishedVertices.top();
        finishedVertices.pop();

        if(!visited[node]){
            dfs_reverse(edgesT, visited, SCC, node, k);
            k++;
        }
    }

    int flag = 1;
    vector<int> ans;
    vector<int> bottom;
    for(int i = 0 ; i < k ; i++){
        for(int j = 0 ; j < SCC[i].size(); j++){
            ans.push_back(SCC[i][j]);
        }
        for(int m = 0 ; m < ans.size() ; m++){
            int node = ans[m];
            for(int j = 0 ; j < edges[node].size() ; j++){
                int new_node = edges[node][j];
                vector<int> :: iterator it;
                it = find(ans.begin(), ans.end(), new_node);
                if(it == ans.end()){
                    flag = 0;
                    break;
                }
            }
            if(flag == 0)
                break;
        }
        if(flag == 1){
            for(int j = 0 ; j < ans.size() ; j++)
                bottom.push_back(ans[j]);
        }
        flag = 1;
        ans.clear();
    }
    sort(bottom.begin(), bottom.end());
    for(int i = 0 ; i < bottom.size() ; i++)
        cout << bottom[i] + 1 << " ";
    cout << endl;
}

int main(){
    while(true){
        int n;
        cin >> n;
        if(n == 0)
            break;

        vector<int>* edges = new vector<int>[n];
        vector<int>* edgesT = new vector<int>[n];
        int e;
        cin >> e;
        for(int i = 0 ; i < e ; i++){
            int x, y;
            cin >> x >> y;
            edges[x-1].push_back(y-1);
            edgesT[y-1].push_back(x-1);
        }

        getSCC(edges, edgesT, n);

        delete [] edges;
        delete [] edgesT;
    }
    return 0;
}