拓扑排序专题

牢记:拓扑排序得出的ans是一个序列

思路:确定正向or逆向排序 ; 入度为0入队列,队列里的都是答案,每一个答案对应的边顶点   --入度,为0入队列

来模板(第一题)

复杂度O(n+e)

#include <stdio.h>
#include <iostream>
#include <math.h>
#include <map>
#include <algorithm>
#include <string.h>
#include <vector>
#include <queue>

using namespace std;

const int MAXN=505;
int indegree[MAXN];
vector <int> edge[MAXN];

void init(int n)
{
    memset(indegree,0,sizeof(indegree));
    for(int i=1;i<=n;i++)   edge[i].clear();
}


int main(void)
{
    int n,m;
    while((scanf("%d%d",&n,&m))==2)
    {
        init(n);
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            indegree[y]++;
            edge[x].push_back(y);
        }
        vector <int> ans;
        priority_queue <int,vector<int>,greater<int> >temp;
        for(int i=1;i<=n;i++)
            if(indegree[i]==0)  temp.push(i);
        while(!temp.empty())
        {
            int v=temp.top();temp.pop();
            ans.push_back(v);
            for(int i=0;i<edge[v].size();i++)
                if(--indegree[edge[v][i]]==0) temp.push(edge[v][i]);
        }
        for(int i=0;i<ans.size();i++)
        {
            if(i!=ans.size()-1)    printf("%d ",ans[i]);
            else    printf("%d\n",ans[i]);
        }
    }

}
常见问题:

1.是否有环(有向图topsort/无向图并查集)

2.反向拓扑(一定大小关系,小的尽量考前)

3.拓扑排序的唯一解问题

1:HDU-1285

题意:已知有n个队伍,m个关系对(X在Y前面),输出一个解

思路:基础拓扑


2:HDU-3342

题意/思路:与上雷同


3:HDU-2647

题意:n个人,m个关系(X的工资比Y高,基础工资均为888),问至少要付多少工资

思路:反向拓扑indegree[y]++,edge[x].push_back(x)


4:HDU-4857

题意:n个人,m对关系(x<y)并且小的尽量考前

思路:反向拓扑+优先队列(大的优先)  , 反向输出

#include <stdio.h>
#include <iostream>
#include <math.h>
#include <map>
#include <algorithm>
#include <string.h>
#include <vector>
#include <queue>

using namespace std;

const int MAXN=30000+5;
int indegree[MAXN];
vector <int> edge[MAXN];

void init(int n)
{
    memset(indegree,0,sizeof(indegree));
    for(int i=1;i<=n;i++)   edge[i].clear();
}

int main(void)
{
    int n,m;
    int t;
    cin >>t;
    while(t--)
    {
        cin >>n >>m;
        init(n);
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            indegree[x]++;
            edge[y].push_back(x);
        }
        vector <int> ans;
        priority_queue <int> temp;
        for(int i=1;i<=n;i++)
            if(indegree[i]==0)  temp.push(i);
        while(!temp.empty())
        {
            int v=temp.top();temp.pop();
            ans.push_back(v);
            for(int i=0;i<edge[v].size();i++)
                if(--indegree[edge[v][i]]==0) temp.push(edge[v][i]);
        }
        for(int i=ans.size()-1;i>=0;i--)
        {
            if(i!=0)    printf("%d ",ans[i]);
            else    printf("%d\n",ans[i]);
        }
    }
}


5:HDU-5222

题意:给一个有向边和无向边组成的图,问是否存在环

思路:有向图topsort+考虑并查集  /  无向图并查集


6:HDU-3687

题意/思路:雷同HDU-4857


7:POJ-2367

题意/思路:雷同1,是最基础的拓扑。


8.POJ-1094

题意:给定n和m(m对关系,a<b表示a要在b前面),输出是否矛盾;不矛盾的话 是否有唯一解?  矛盾和唯一解的情况输出由第几条信息判断完毕。

思路:每次输入一组数据都要topsort一次,判断是否矛盾就是判断是否有环。唯一解的要求是在每次入队列的时候,que.size()==1,即每次寻找入度为0的并且没vis过的,只有一个。

#include <stdio.h>
#include <map>
#include <vector>
#include <queue>
#include <iostream>
#define bug cout <<"woc"<<endl
using namespace std;

const int MAXN=100;

int indegree[MAXN];
vector <int> edge[MAXN];
int indegreerecord[MAXN];
vector<int> edgerecord[MAXN];
int l;

void comeback(int n)
{
    for(int i=1;i<=n;i++)
        indegree[i]=indegreerecord[i];
    for(int i=1;i<=n;i++)
    {
        edge[i].clear();
        for(int j=0;j<edgerecord[i].size();j++)
        {
            edge[i].push_back(edgerecord[i][j]);
        }
    }
}

void init(int n)
{
    for(int i=1;i<=n;i++)
        indegree[i]=0,edge[i].clear(),indegreerecord[i]=0,edgerecord[i].clear();
}

int topsort(int n)
{
    int cnt=0,sc=0;
    bool flag=true;
    vector <int> ans;
    priority_queue <int>temp;
    for(int i=1;i<=n;i++)
        if(indegree[i]==0)  temp.push(i);
    //int c=temp.size();
    //if(c==0)    return -1;
    //if(c>=2)    return 0;   //wa的地方,因为>=2可能会有矛盾的情况
    //else
    //{
        while(!temp.empty())
        {
            cnt=0;
            for(int i=1;i<=n;i++)
                if(indegree[i]==0)  cnt++;
            if(cnt!=sc+1)   flag=false;
            else if(cnt==sc+1)  sc++;
            int v=temp.top();temp.pop();
            ans.push_back(v);
            for(int i=0;i<edge[v].size();i++)
                if(--indegree[edge[v][i]]==0)   temp.push(edge[v][i]);
        }
    //}
    if(ans.size()!=n)
    {
        return -1;
    }
    else
    {
        if(flag==true)
        {
            printf("Sorted sequence determined after %d relations: ",l);
            for(int i=0;i<ans.size();i++)
                printf("%c",ans[i]+'A'-1);
            printf(".\n");
            return 1;
        }
        else        return 0;
    }
}

int main(void)
{
    int n,m;
    while(cin>>n>>m)
    {
        int flag=0;
        if(n==0 && m==0)    break;
        init(n);
        for(int i=1;i<=m;i++)
        {

            char str[5];
            scanf("%s",str+1);
            if(flag==-1 || flag==1) continue;l=i;
            int x=str[1]-'A'+1;
            int y=str[3]-'A'+1;
            indegree[y]++;indegreerecord[y]++;
            edge[x].push_back(y);edgerecord[x].push_back(y);
            flag=topsort(n);
            comeback(n);

        }
        if(flag==-1)
            printf("Inconsistency found after %d relations.\n",l);
        else if(flag==0)
            printf("Sorted sequence cannot be determined.\n");
    }
}


https://vjudge.net/contest/199005#overview

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值