码迷,mamicode.com
首页 > 编程语言 > 详细

浅谈拓扑排序在OI的应用

时间:2015-04-16 23:08:42      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:

浅谈拓扑排序在OI的应用

by MedalPluS

  【拓扑排序的定义】

    引例:

      在大学里有很多学科需要学习,而有的学科需要学习其他学科后才能学习,比如说必须先学数学再学微积分......这就是一个拓扑序的关系

  【拓扑排序的应用】

    对于上述题目,可以假设如果学习a需要学习b的话,从b连一条边到a,然后对整个图求一次拓扑序列,这便是学习的一种方案

    技术分享

    很显然,拓扑排序应该从入度为0,然后1,然后2...来找

  【拓扑排序的实现】

    很容易想到一种算法,暴力枚举每个点,然后找与之相连的点,删掉这条边,并把点的入度-1,再次寻找,知道找不到为止

    裸的算法为O(n2)

    我们发现,拓扑排序的结果是拓扑序,那么可以用队列来改造,而枚举边又耗时,所以就用邻接表来存储

    时间复杂度O(n+e)

  【拓扑排序在OI的应用】

    例题1.郁闷的记者

    【问题描述】
      你是一个体育报社的记者,你接受到一项艰难的任务:有N支足球队参加足球比赛,现在给你一些比赛的结果,需要你给你各支球队的排名,从1到N。
   以下是给你的一些信息:
  (1)没有平局;
  (2)不同的球队排名不能相同;
  (3)对于所有满足1≤a<b≤N,第a名的球队一定可以打败第b名的球队。
   给你部分比赛结果,要求给出排名。
   【输入格式】
    第一行输入N(1≤N≤5000),表示球队的数量,编号为1到N。

    第二行输入M(1≤M≤100000),表示给出的比赛场数。接下来M行,每行两个整数xi,yi,表示球队xi能打败球队yi。
   【输出格式】
     输出包含N行,前N行描述球队的排名,第i个数表示排名为i的球队编号。

   【分析】

     我们可以建立一个模型,假设每个球队是一个点,那么如果a能打败b则从a到b连一条有向边。

     由于求排名,很明显,入度为0的第一,其次第二,第三....

     发现没?这便是拓扑排序的模板!

     我们使用o(N+e)的代码,见附录1        


 

      例题2.奇怪的梦境

    题目描述 Description
    Aiden陷入了一个奇怪的梦境:他被困在一个小房子中,墙上有很多按钮,还有一个屏幕,上面显示了一些信息。屏幕上说,要将所有按钮都按下才能出去,而又给出了一些信息,说明了某个按钮只能在另一个按钮按下之后才能按下,而没有被提及的按钮则可以在任何时候按下。可是Aiden发现屏幕上所给信息似乎有矛盾,请你来帮忙判断。

    输入描述 Input Description
    第一行,两个数N,M,表示有编号为1...N这N个按钮,屏幕上有M条信息。

    接下来的M行,每行两个数ai,bi,表示bi按钮要在ai之后按下。所给信息可能有重复,保证ai≠bi。

   输出描述 Output Description
   若按钮能全部按下,则输出“o(∩_∩)o”。

   若不能,第一行输出“T_T”,第二行输出因信息有矛盾而无法确认按下顺序的按钮的个数。输出不包括引号。

  样例输入 Sample Input
  3 3

  1 2

  2 3

  3 2

  样例输出 Sample Output
  T_T

  2

  数据范围及提示 Data Size & Hint
  对于30%的数据,保证0<N≤100。

  对于50%的数据,保证0<N≤2000。

  对于70%的数据,保证0<N≤5000。

  对于100%的数据,保证0<N≤10000,0<M≤2.5N。

 【分析】

   首先,不难发现题目是求拓扑排序(0.0),把每个按钮抽象1成点,a在b之前则从a连一条到b的边,然后求拓扑排序,统计有多少个点没有被扫到

   时间复杂度O(n+m),不会TLE

   代码见附录2


 

 【总结】

  附录1.

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <queue>
 4 using namespace std;
 5 
 6 const int maxn=5001;
 7 const int maxm=1000001;
 8 
 9 int in[maxn];
10 int n,m,u,v;
11 
12 struct edge{
13     int next,to;
14 }g[maxm];
15 
16 int head[maxn],cnt;
17 
18 void addedge(int u,int v){
19     cnt++;
20     g[cnt].to=v;
21     g[cnt].next=head[u];
22     head[u]=cnt;
23 }
24 
25 queue<int> q;
26 void top_sort(){
27     int u,i,j;
28     for(i=1;i<=n;i++)
29       if(!in[i])q.push(i);
30     while(!q.empty()){
31         u=q.front();
32         cout<<u<<endl;
33         q.pop();
34         for(j=head[u];j;j=g[j].next)
35         {
36           in[g[j].to]--;
37           if(in[g[j].to]==0)
38             q.push(g[j].to);
39         }
40     }
41 }
42 
43 int main(){
44     freopen("rank.in","r",stdin);
45     freopen("rank.out","w",stdout);
46     cin>>n>>m;
47     int i;
48     for(i=1;i<=m;i++){
49         scanf("%d%d",&u,&v);
50         addedge(u,v);
51         in[v]++;
52     }
53     top_sort();
54     return 0;
55 }

  附录2.

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;

const int maxn=25005;

struct edge{
    int next,to;
}g[maxn];

int head[maxn],cnt;
int n,m,in[maxn];
int inq;

void addedge(int u,int v){
    cnt++;
    g[cnt].to=v;
    g[cnt].next=head[u];
    head[u]=cnt;
}

void topsort(){
    queue<int> q;
    int i,ahead;
    for(i=1;i<=n;i++)
      if(!in[i])
        q.push(i);
    while(!q.empty()){
      ahead=q.front();
      q.pop();
      inq++;
      for(i=head[ahead];i;i=g[i].next)
      {
          in[g[i].to]--;
          if(in[g[i].to]==0)q.push(g[i].to);
      }
    }
    if(inq==n)cout<<"O(∩_∩)O";
    else cout<<"T_T"<<endl<<n-inq; 
}

int main(){
    cin>>n>>m;
    int u,v;
    for(int i=1;i<=m;i++){
      scanf("%d%d",&u,&v);
      addedge(u,v);
      in[v]++;
    }
    topsort();
    return 0;
}

 

浅谈拓扑排序在OI的应用

标签:

原文地址:http://www.cnblogs.com/maopengsen/p/4433373.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!