hdu 拓扑排序归纳

拓扑排序,其本质是输出一个全序关系,对于按要求输出给定关系的题目,一般就是按照题目要求实现这个全序关系,这种题时常会先给一个偏序关系,然后给出剩下的元素如何建立关系(字典序之类的)。

如果忘了那几个词是啥意思...

      偏序关系:满足自反,反对称,传递性的关系

      全序关系:一个偏序关系R,且对任意x,y有xRy或yRx

      哈斯图:对一个偏序关系画的图,每个点为关系中的元素,其中,对两点x,y,若有xRy则y画在x上方,若有xRy且不存在s满足xRs,sRy则在x,y中连线。一般情况下把题目里面给的关系直接画出来再分下层就是哈斯图了。和正常的哈斯图不同,为了方便看我们一般会在上面标上箭头。

    拿下面这个图说事,按之前的说法,6-2和6-1都在这个偏序关系里面(传递性)但是因为6和1里面连着2就不在他俩连线了,同样对于拓扑排序的题,题目里面说了6-2和2-1以后由传递性就有6-1了,不要拘泥于概念

hdu 拓扑排序归纳_第1张图片

画上箭头。拓扑排序的效果在于把偏序关系线性输出,在这个里面5,6,7之间没有确定的顺序,还有就是可以按照8-5-6-2这样的顺序,在7之前输出2,没有说同层的必须连着输出。对于这种状况按什么顺序输出是一个考点,经常会把这个顺序根点的标号扯上关系,加上拓扑排序里面用到一个队列,所以时常会在此处把队列操作成优先队列

hdu 拓扑排序归纳_第2张图片

然后就是拓扑排序可以用于判断有向环,如果在排序中排出来的点比图上的总点数少就说明有有向环。如果一个关系里面出现了环,自然就不满足反对称性了(ex:xRy,yRz,zRx则由传递性有xRz与zRx一起不满足反对称性),然后它就不是一个偏序关系了,所以如果判出来了环的情况论上就不会有下一步操作了。无向环用并查集判断

另外还有的题就是要你确定一个偏序关系,比如统计同样的偏序(可以理解为哈斯图上面同一层的元素)每个有多少

因为拓扑排序这个东西本身比较直观符合大众认知,直接给个裸的拓扑排序显得太亲民,所以如果看见他出现,一般都会是绕了几个弯,变成一道智商题,想直接写一个拓扑排序然后就过了不大现实,搞清楚拓扑排序的思想比较重要,方便在关键时刻能够胡搞的出来。

常用操作:

 反向建图:有时会出现=需要把题目所给的偏序反过来的情况,比如下面的2647

 把队列换成优先队列

hdu1285

比较纯的拓扑排序,因为要按照字典序输出拓扑序相同的元素,以及时间多,所以可以不使用队列而是暴力遍历

#include 

using namespace std;
const int maxn=500;
int main()
{
    int v,e;
    while(cin>>v>>e)
    {
        vectorvec;
        vector mp[maxn];
        int deg[maxn],s,t;
        memset(deg,0,sizeof(deg));
        for(int i=1;i<=e;i++)
        {
            cin>>s>>t;
            deg[t]++;
            mp[s].push_back(t);
        }

        for(int i=1;i<=v;i++)
        {
            for(int j=1;j<=v;j++)
            {
                if(deg[j]==0)
                {
                    for(int k=0;k

hdu3342

拓扑排序判断有向环的题目,对于判环的题,判无向环一般用并查集,判有向环一般用拓扑排序

#include 

using namespace std;

int main()
{
    vector adjl[105];
    int v,e,s,t,in[105];
    bool vis[105];
    while(cin>>v>>e,v!=0)
    {
        memset(adjl,0,sizeof(adjl));
        memset(vis,0,sizeof(vis));
        memset(in,0,sizeof(in));
        for(int i=0;i>s>>t;
            adjl[s].push_back(t);
            in[t]++;
        }
        int coun=v;
        queue q;
        for(int i=0;i
hdu2647

使用拓扑排序判环并且判断点在拓扑序上的层次,我的思路是维护两个值,一个值记录现在的层次,另一个值维护当前层次下,队列中还有多少个元素。另外还要反向建图

#include 

using namespace std;

int main()
{
    vector adjl[10005];
    int v,e,s,t,in[10005],deg[10005];
    bool vis[10005];
    while(cin>>v>>e)
    {
        memset(adjl,0,sizeof(adjl));
        memset(vis,0,sizeof(vis));
        memset(in,0,sizeof(in));
        for(int i=0;i>s>>t;
            adjl[t].push_back(s);
            in[s]++;
        }
        int coun=v;
        queue q;
        int levl=0,cur=0,tot=0;
        for(int i=1;i<=v;i++)
        {
            if(in[i]==0)
            {
                q.push(i);
                vis[i]=true;
                levl++;

            }
        }

     //   for(int i=0;i
hdu1811
这个题是拓扑排序和并查集的结合,需要拿并查集预处理后拿拓扑排序判断是否有唯一拓扑序和是否有拓扑序

#include 

using namespace std;
const int maxn=10005;
int fa[maxn];

int findfa(int vt)
{
    if(vt!=fa[vt]) fa[vt]=findfa(fa[vt]);
    return fa[vt];
}
struct edge
{
    int from,to;
    char op;
}ed[maxn*2];

int main()
{

    int v,e,s,t,in[maxn];
    vector adjl[maxn];
    while(~scanf("%d%d",&v,&e))
    {
        for(int i=0;i')
            {
                adjl[x].push_back(y);
                in[y]++;
            }
            else{adjl[y].push_back(x);in[x]++;}
        }
        queueq;
        for(int i=0;i1)flag=true;
            int vt=q.front();
            q.pop();
            sum--;//cout<<"  !"<0)cout<<"CONFLICT"<

hdu 5695

这个题把拓扑排序用的队列换成优先队列以后再处理一下就行了

#include 

using namespace std;
vector adjl[100010];
    long long c,su;
    int v,e,s,t,in[100010];int ans[100010],countt;
void top_sort()
{priority_queue q;
 for(int i=v;i>=1;i--)

            if(in[i]==0)

                q.push(i);

     while(!q.empty())
        {

            int vt=q.top();
            q.pop();
            ans[countt++]=vt;


            //c=min((long long)vt,c);

            //su+=cans[i]?ans[i]:c;
            su+=c;
        }
    printf("%I64d\n",su);
        //for(int i=0;i

hdu4857

反向建图,大根堆做队列,反向输出

#include 

using namespace std;
const int maxn=30005;
int main()
{
    int v,e,in[maxn];
    bool vis[maxn];
    int tt;
    vector adjl[maxn];scanf("%d",&tt);
    while(tt--)
    {scanf("%d %d",&v,&e);
        for(int i=1;i<=v;i++)
        {
            adjl[i].clear();
            in[i]=0;
            vis[i]=false;
        }
        int fr,to;
        for(int i=1;i<=e;i++)
        {
            scanf("%d %d",&fr,&to);
            adjl[to].push_back(fr);
            in[fr]++;
        }
        int coun=1;
        //top_sort;
        priority_queueq;
        vectorvec;
        for(int i=1;i<=v;i++)if(in[i]==0){q.push(i);}
        while(!q.empty())
        {
            int vt=q.top();
            vec.push_back(vt);
         //   cout<0;i--)printf("%d ",vec[i]);
        printf("%d\n",vec[0]);
    }
    return 0;
}




你可能感兴趣的:(拓扑排序)