UVA10305 Ordering Tasks(有向无环图排序--toposort) Kahn算法

Posted zzozz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVA10305 Ordering Tasks(有向无环图排序--toposort) Kahn算法相关的知识,希望对你有一定的参考价值。

题目描述:https://vjudge.net/problem/UVA-10305

 

题目分析:

  恨水的题目,只要学了toposort就会做的,大概意思是给你n个变量,m个不等关系表示a<b,问n个数可能的关系;不如举个例子例如n=3表示3个变量我们假如他们是a,b,c现在有两个关系a<b,a<c

那么输出有两种a<b<c或者a<c<b(题目要求输出任意一种);

  题目大概就这个意思,那么我们怎么做呢,我们想一想如果把变量看成点,关系看成有向边,那么就得到一个图,这个图有一些特殊的性质:

    1.如果对于一个点有入度(即有一个或以上的另一个点可以到达这个点),那么这个点对应的变量一定不是最小的(很好理解对吧).

    2.如果一个点入度等于0(即没有点可以到达它),那么它可能是最小的(想一想,为什么),当然如果一个点没有出度(即它不能到达其它点),它就可能是最大的.

    3.满足题意的条件下,图中不可能有环,因为如果有环说明一定可以从一个点出发回到当前点,那么就有这个点对应的变量小于它自己(肯定不可能了),如3<3就明显不可能(这也是为什么无向图和有环图没有toposort的原因了).

  知道了这些性质有什么用呢?有的读者就发现,是不是可以通过图来确定不等关系.因为题目要求输出可能的不等关系,那么我们可以现找到一个可能为最小的数,把它做为第一个数字来输出.这样我们就知道了最小的可能变量,那么我们怎么继续找第二个呢,我们想一想,最小的找到后,他能到达的第一个点是不是都可能是第二小的变量,那么我们只需要把这个点和与他相连的边删掉(实际只有指向其它点的边,因为入度为0).只需要一直重复这个操作,就可以完成求解了.实际上这个确定不等关系有个很牛逼(介于牛A牛C之间)的名字,那就是拓扑排序(即toposort).

  上面说到了只有有向无环图才有toposort,现在给出解释,因为toposort是将图(准确的说是有向无环图),排列成一个线性关系的过程,那么如果存在环,就有一个点的入度一定不为0,到最后就是死循环了(看了后面代码就知道了)...实际上也可以通过实数的大小关系来理解因为不存在一个数使他自己小于他自己,所以肯定不能有环呀,那么无向图又是什么情况呢?无向图是不是就是从任意有边的点可以互相到达,那么这不就是环了(a-b,b-a==a-a).

  那么下面讲讲代码怎么写(终于讲重点了是不是...)...

  首先我们需要将图保存起来,用矩阵,邻接表都行,因为题目最多100个变量,也就是最多100个点,用矩阵就要好写的多...

  用一个ans数组表示可能得不等关系,用indefree表示一个点的入度(也就是有多少点可以到这个点).

  那么我们看看代码实现....

丑陋的代码:

#include<bits/stdc++.h>

const int maxn = 101;

using namespace std;

int n,m;
bool G[maxn][maxn];
int indegree[maxn];
int ans[maxn];

void toposort(){//核心代码
    queue<int> q;//可以用栈,影响不大,也可以手写
    int cnt=0;//表示排了几个变量了
    for(int i=0;i<n;i++)
        if(indegree[i]==0) q.push(i);//根据分析描述先找入度为零的,放到队列里准备处理
    while(!q.empty()){
        int tmp=q.front();//找出一个当前可能最小的
        q.pop();//扔掉
        ans[cnt++]=tmp;//放到ans数组里
        for(int i=0;i<n;i++)//灵魂所在
            if(G[tmp][i]==1&&(--indegree[i]==0)) q.push(i);
            //删除点和边的操作,但实际并不需要删除,因为有个队列,队列里的顺序是一种可能的顺序,删除点后又要放进去入度为0的,不如直接放进去
    }
    //输出
    cout<<ans[0]+1;
    for(int i=1;i<cnt;i++) cout<<" "<<ans[i]+1;
    cout<<endl;
}
int main(){
    ios::sync_with_stdio(false);
    while(cin>>n>>m&&(m||n)){//输入不解释
        memset(G,0,sizeof(G));
        memset(indegree,0,sizeof(indegree));//初始化
        int a,b;
        for(int i=0;i<m;i++){
            cin>>a>>b;
            G[a-1][b-1]=true;//矩阵存图
            indegree[b-1]++;//入度(没有一个点可以到达b  那么b点的入度就增加1)
        }
        toposort();
    }
    return 0;
}

  就到这里,溜了溜了,不懂就问qq624626089...

以上是关于UVA10305 Ordering Tasks(有向无环图排序--toposort) Kahn算法的主要内容,如果未能解决你的问题,请参考以下文章

Uva10305 Ordering Tasks

UVa 10305 - Ordering Tasks (拓扑排序裸题)

Uva 10305 Ordering Tasks(拓扑排序模版题)

UVA 10305 Ordering Tasks (拓扑排序)

给任务排序 Ordering Tasks UVA10305

UVA10305 Ordering Tasks