UVA-10305 Ordering Tasks (拓扑排序)

题目大意:给出n个点,m条关系,按关系的从小到大排序。

题目分析:拓扑排序的模板题,套模板。

 

kahn算法:

伪代码:

Kahn算法:

摘一段维基百科上关于Kahn算法的伪码描述:

L← Empty list that will contain the sorted elements
S ← Set of all nodes with no incoming edges
while S is non-empty do
    remove a node n from S
    insert n into L
    foreach node m with an edge e from nto m do
        remove edge e from thegraph
        ifm has no other incoming edges then
            insert m into S
if graph has edges then
    return error (graph has at least onecycle)
else
    return L (a topologically sortedorder)

维护一个入度为0的点的集合S,一个初始为空的集合L,L存放排好序的序列。将集合S中的一个点加入集合L后,在S中删除该点并破坏所有从该点出发的边,若被破坏的边的另一端点的入度为0,则加入S,一直处理到S为空。若仍有边存在,则存在环路,反之,集合L中的元素便是按拓扑序排放的。时间复杂度为O(E+V)。

代码如下:

# include<iostream>
# include<cstdio>
# include<queue>
# include<vector>
# include<cstring>
# include<algorithm>
using namespace std;

int mp[105][105],n,m,d[105];
vector<int>l;
queue<int>q;

int judge(int u)
{
    int cnt=0;
    for(int i=1;i<=n;++i)
        if(mp[i][u])
            ++cnt;
    return cnt;
}

void solve()
{
    l.clear();
    while(!q.empty()){
        int u=q.front();
        q.pop();
        l.push_back(u);

        for(int i=1;i<=n;++i){
            if(mp[u][i]){
                mp[u][i]=0;
                --d[i];
                if(d[i]==0)
                    q.push(i);
            }
        }
    }
    for(int i=0;i<n;++i)
        printf("%d%c",l[i],(i==n-1)?'\n':' ');
}

int main()
{
    int a,b;
    while(scanf("%d%d",&n,&m)&&(n+m))
    {
        memset(mp,0,sizeof(mp));
        while(m--){
            scanf("%d%d",&a,&b);
            mp[a][b]=1;
        }

        while(!q.empty())
            q.pop();
        for(int i=1;i<=n;++i){
            d[i]=judge(i);
            if(d[i]==0)
                q.push(i);
        }
        solve();
    }
    return 0;
}

  

基于dfs的拓扑排序:

同样摘录一段维基百科上的伪码:

L ← Empty list that will contain the sorted nodes
S ← Set of all nodes with no outgoing edges
for each node n in S do
    visit(n)
function visit(node n)
    if n has not been visited yet then
        mark n as visited
        for each node m with an edgefrom m to ndo
            visit(m)
        add n to L

维护一个出度为0的点的集合S,一个初始为空的集合L,L存放排好序的序列。对于集合S中的一个点e,先将所有应该排在e前面的点放到集合L之后,再将点e放入集合L。时间复杂度为O(E+V)。

代码如下:

# include<iostream>
# include<cstdio>
# include<queue>
# include<vector>
# include<cstring>
# include<algorithm>
using namespace std;

vector<int>l;
queue<int>q;
int n,m,mp[105][105],mark[105];

bool judge(int u)
{
    for(int i=1;i<=n;++i)
        if(mp[u][i])
            return false;
    return true;
}

void visit(int u)
{
    if(!mark[u]){
        mark[u]=1;
        for(int i=1;i<=n;++i)
            if(mp[i][u])
                visit(i);
        l.push_back(u);
    }
}

void solve()
{
    l.clear();
    memset(mark,0,sizeof(mark));
    while(!q.empty()){
        int u=q.front();
        q.pop();
        visit(u);
    }
    for(int i=0;i<n;++i)
        printf("%d%c",l[i],(i==n-1)?'\n':' ');
}

int main()
{
    int a,b;
    while(scanf("%d%d",&n,&m)&&(n+m))
    {
        memset(mp,0,sizeof(mp));
        while(m--)
        {
            scanf("%d%d",&a,&b);
            mp[a][b]=1;
        }

        while(!q.empty())
            q.pop();
        for(int i=1;i<=n;++i){
            if(judge(i))
                q.push(i);
        }
        solve();
    }
    return 0;
}

  

posted @ 2015-10-06 15:59  20143605  阅读(265)  评论(0编辑  收藏  举报