poj 2367 拓扑排序

题目链接:http://poj.org/problem?id=2367

题目大意:就是进行拓扑排序,先给你一个数n,代表1~n,对于每个数有一系列的指向,最后将这些数进行排列出来。。就是简单的拓扑排序。

首先拓扑排序应该有两种实现的方法。。

一种是用dfs进行每个节点的搜索,最后进行回溯,这样的话很容易就能明白先找出来的应该是后面的数,而最后找出来的应该是之前的数,因为是回溯出来的嘛。。所以可以使用一个栈来进行答案的存储,因为栈的特性就是后压入的先弹出。

dfs实现的思想:利用一个数组来存储每个顶点的状态,-1代表正在栈帧中(也就是还在调用dfs尚未返回),0表示还未进行访问,1表示调用过dfs并已经返回。。

在使用一个二维数组来进行元素之间指向的标记,比如1指向2,就让G[1][2]=1;

实现的方法就是对于每个节点尝试进行dfs,(也就是说如果他未被访问过,则调用dfs),而每个节点进入dfs之后,再找到这个节点所指向的节点,如果不出现环的话,就再对这个节点进行dfs,这样一直下去,直到有一个点没有指向,最后就会将这个点标记为已访问,并且压入储存答案的栈,再返回 true,表示成功进行dfs,之后就会回溯,这样下去就会找到一开始的头节点,因为拓扑排序对每个节点都尝试进行这样的操作,所以最后就可以将其排序出来。

要点:感觉dfs实现的要点就在于标记节点,以及如何判断是否出现环,如果一个节点指向的一个节点的标记为-1,也就是说其还在栈中,那么就可以判断是有环的。

dfs代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
#define M 1000
int vis[M];
int G[M][M];
stack<int> s; //用于储存答案
int n;
bool dfs(int u)
{
    vis[u] = -1;
    for(int i = 1;i <= n;i++)
    {
        if(G[u][i])
        {
            if(vis[i]<0) return false;  //该元素正在调用dfs,意味着有环。。
            if(!vis[i] && !dfs(i)) return false; //如果没有访问过,并且这个节点调用dfs返回false
        }
    }
    vis[u] = 1;  //标记成功调用并返回。
    s.push(u);   //将该节点压入栈中
    return true;
}
bool toposort()
{
    memset(vis,0,sizeof(vis));
    for(int i = 1;i <= n;i++)//遍历每个节点
    {
        if(!vis[i])
        {
            if(!dfs(i)) return false; //有环
        }
    }
    return true;
}
int main()
{
    cin >> n;
    for(int i = 1;i <= n;i++)
    {
        for(;;)
        {
            int temp;
            cin >> temp;
            if(temp == 0) break;    //输入直到0
            G[i][temp] = 1;
        }
    }
    toposort();
    cout << s.top();
    s.pop();
    while(!s.empty())
    {
        cout << " " << s.top(); //格式控制
        s.pop();
    }
    cout <<endl;
    return 0;
}

拓扑排序还可以使用bfs,利用队列来进行实现。。

主要的思想就是用一个数组来存储每个节点的入度,并且用一个vector的数组来存储每一个节点所指向的节点。就可以遍历所有节点,找出入度为一的节点,使其入队,然后再对这个节点所指向的节点遍历,将他们的入度都减1,如果入度变为0,就也进入队列中。对于bfs来说要判断是否有环的话,如果队列中出现的节点的个数小于总共节点的个数,那么一定是出现了环。因为环的话每个节点的入度都为1,没有0的。

还有就是答案因为是正序的所以我们可以用一个队列来存储输出。。

个人感觉还是bfs比较好想一点。。暴露了弱渣的本质orzzzzzzzzzz

bfs代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define M 10000
int s[M]; //in
vector<int> G[M];
int n;
queue<int> ans;
void toposort()
{
    queue<int> q;
    for(int i = 1;i <= n;i++)
    {
        if(s[i]==0)
            q.push(i);
    }
    while(!q.empty())
    {
        int cur = q.front();
        q.pop();
        ans.push(cur);
        for(int i = 0;i < G[cur].size();i++)
        {
            s[G[cur][i]]--;
            if(s[G[cur][i]]==0)
                q.push(G[cur][i]);
        }
    }
}
int main()
{
    cin >> n;
    for(int i = 1;i <= n;i++)
       G[i].clear();
    for(int i = 1;i <= n;i++)
    {
        for(;;)
        {
            int temp ;
            cin >> temp;
            if(temp==0) break;
            s[temp]++;
            G[i].push_back(temp);
        }
    }
    toposort();
    cout << ans.front();
    ans.pop();
    while(!ans.empty())
    {
        cout << " " << ans.front();
        ans.pop();
    }
    cout << endl;
    return 0;
}
时间: 2024-12-21 20:52:16

poj 2367 拓扑排序的相关文章

poj 4084:拓扑排序

poj 4084:拓扑排序 很好的题目,恶心的算法 描述 给出一个图的结构,输出其拓扑排序序列,要求在同等条件下,编号小的顶点在前. 输入 若干行整数,第一行有2个数,分别为顶点数v和弧数a,接下来有a行,每一行有2个数,分别是该条弧所关联的两个顶点编号. v<=100, a<=500 输出 若干个空格隔开的顶点构成的序列(用小写字母). 样例输入 6 8 1 2 1 3 1 4 3 2 3 5 4 5 6 4 6 5 样例输出 v1 v3 v2 v6 v4 v5 解题方案 显然这是有向图,然

Poj 1094 拓扑排序 水题

Sad..这么水的题WA了无数发,题目要看仔细啊,留下来做个警告把 #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #i

poj 1094 拓扑排序

Description An ascending sorted sequence of distinct values is one in which some form of a less-than operator is used to order the elements from smallest to largest. For example, the sorted sequence A, B, C, D implies that A < B, B < C and C < D.

POJ 3249 拓扑排序+DP

貌似是道水题.TLE了几次.把所有的输入输出改成scanf 和 printf ,有吧队列改成了数组模拟.然后就AC 了.2333333.... Description: MR.DOG 在找工作的过程中呢.遇见了这样一个问题.有n个城市,m条小道.然后要从入度为0的点出发,出度为0的点结束,中途经过的城市呢,都是要付费的.负数表示花费.正数表示收益.然后让你求收益最大或者说花费最少的总值. 貌似.BFS和DFS都会超时.不妨一试.附代码: #include<stdio.h>#include<

poj 3687 拓扑排序

Description Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them with 1 to N in such a way that: No two balls share the same label. The labeling satisfies several constrains like "The ball labeled with a is lighter

图论之拓扑排序 poj 2367 Genealogical tree

题目链接 http://poj.org/problem?id=2367 题意就是给定一系列关系,按这些关系拓扑排序. #include<cstdio> #include<cstring> #include<queue> #include<vector> #include<algorithm> using namespace std; const int maxn=200; int ans; int n; int in[maxn]; //记录入度

POJ 2367:Genealogical tree(拓扑排序)

Genealogical tree Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 2738 Accepted: 1838 Special Judge Description The system of Martians' blood relations is confusing enough. Actually, Martians bud when they want and where they want. They ga

POJ 2367 Genealogical tree 拓扑排序入门

Description The system of Martians' blood relations is confusing enough. Actually, Martians bud when they want and where they want. They gather together in different groups, so that a Martian can have one parent as well as ten. Nobody will be surpris

POJ 2367 (裸拓扑排序)

http://poj.org/problem?id=2367 题意:给你n个数,从第一个数到第n个数,每一行的数字代表排在这个行数的后面的数字,直到0. 这是一个特别裸的拓扑排序的一个题目,拓扑排序我也是刚刚才接触,想法还是挺简单的.实现起来也不复杂. 1 #include <stdio.h> 2 #include <string.h> 3 4 int Indegree[101],n; 5 6 bool mp[101][101]; 7 8 int topsort() 9 { 10