[拓扑排序]Day 3 提高组模拟C组 T3 头晕的奶牛

题目链接

https://www.luogu.org/problemnew/show/P2017

题目大意

给定一张 n 点, m 1 条有向边, m 2 条无向边,现要给每条无向边一个方向,使这张图变成一张有向无环图

解题思路

T o p s o r t :将一张有向无环图的元素进行排序使其满足拓扑次序

注:紫色为已出队,红色为当前准备拓展点,蓝色为被拓展点,黄色为还在队内的已被拓展点
具体实现如下:
首先读入 m 1 条有向边,然后找到入度为0的点(可能有多个),将它们入队(入度为0的点的入队顺序不影响结果所以任选一个作为队首都行,所以标红),如下图
1
然后每次以队首进行拓展,将其邻接点的入度统统减少1,若有点的入度变成0了,则将其入队
2
然后让队首出队,继续用下一个队首进行拓展
3
继续扩展
4
再拓展,此时4的出度为0,跳过
5
然后继续拓展
6
继续
7
继续拓展,发现没有入度了,结束
end
此时队列为空,结束

想知道这些图我是怎么画的吗?点这里:https://www.processon.com/i/5afc01e3e4b096c6eeb3834b

代码

#include<queue>
#include<cstdio>
#include<cstring>
#define N 100001
using namespace std;
struct node{int next,to;}e[N<<2];
int rd[N],l[N<<1],n,m1,m2,x,y,t[N],len,tot;
queue<int>q;
void add(int u,int v)
{
    e[tot]=(node){l[u],v};l[u]=tot++;
    return;
}
int main()
{
    freopen("dizzy.in","r",stdin);
    freopen("dizzy.out","w",stdout);
    memset(l,-1,sizeof(l));
    scanf("%d%d%d",&n,&m1,&m2);
    for(int i=1;i<=m1;i++) scanf("%d%d",&x,&y),add(x,y),rd[y]++;
    for(int i=1;i<=n;i++) if(!rd[i]) t[i]=++len,q.push(i);
    while(q.size())
    {
        x=q.front();q.pop();
        for(int j=l[x];~j;j=e[j].next)
        if(!(--rd[e[j].to])) t[e[j].to]=++len,q.push(e[j].to);//拓扑排序
    }
    for(int i=1;i<=m2;i++)
    {
        scanf("%d%d",&x,&y);
        if(t[x]<t[y]) printf("%d %d\n",x,y);else printf("%d %d\n",y,x);//谁更晚入队就连谁
    }
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/80960656
今日推荐