每日OJ题_牛客_AB13【模板】拓扑排序_C++_Java

牛客_AB13【模板】拓扑排序

【模板】拓扑排序_牛客题霸_牛客网 (nowcoder.com)

描述

        给定一个包含nn个点mm条边的有向无环图,求出该图的拓扑序。若图的拓扑序不唯一,输出任意合法的拓扑序即可。若该图不能拓扑排序,输出−1。


题目解析

拓扑排序裸题,步骤:
  1. 建图。
  2. 入队为 0 的点入队。
  3. 最后来一次层序遍历即可。

C++代码

#include <iostream>
#include <queue>
#include <unordered_map>
#include <vector>
using namespace std;
const int N = 2 * 1e5 + 1;
int main()
{
	int n = 0, m = 0;
	cin >> n >> m;
	int x = 0, y = 0;
	unordered_map<int, vector<int>> Edge;
	vector<int> in(N);
	while (cin >> x >> y) // x 指向 y
	{
		Edge[x].push_back(y);
		in[y]++;
	}
	// for(auto& [a, b] : Edge)
	// {
	// cout << a << " -> ";
	// for(auto& e : b)
	// {
	// cout << e << " ";
	// }
	// cout << endl;
	// }
	// for(auto& e : in)
	// {
	// if(e != 0)
	// cout << e << " ";
	// }
	// cout << endl;
	priority_queue<int> q;
	for (int i = 1; i <= n; ++i)
	{
		if (in[i] == 0)
		{
			q.push(i);
			// cout << "begin" << i;
		}
	}
	vector<int> res;
	while (q.size())
	{
		int tmp = q.top();
		q.pop();
		res.push_back(tmp);
		for (auto& e : Edge[tmp]) // tmp指向的边的入度减一
		{
			in[e]--;
			if (in[e] == 0) // 减为0了就进队列
				q.push(e);
		}
		// // Edge.erase(tmp); // 加这步?
		// for(auto& [a, b] : Edge)
		// {
		// cout << a << " -> ";
		// for(auto& e : b)
		// {
		// cout << e << " ";
		// }
		// cout << endl;
		// }
		// for(int i = 1; i <= n; ++i)
		// {
		// cout << in[i] << " ";
		// }
		// cout << endl;
	}
    if(res.size() != n)
    {
        cout << -1;
    }
    else
    {
        for (int i = 0; i < n - 1; ++i)
        {
            cout << res[i] << " ";
        }
        cout << res[n - 1]; // 666666666666666
    }
	return 0;
}

Java代码

import java.util.*;
import java.io.*;
public class Main
{
    public static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    public static Read in = new Read();
    public static int n, m;
    public static Map<Integer, List<Integer>> edges = new HashMap<>(); // 存储图
    public static int[] cnt; //统计⼊度信息

    public static void main(String[] args) throws IOException
    {
        n = in.nextInt(); m = in.nextInt();
        cnt = new int[n + 1];
        // 1. 建图
        for(int i = 0; i < m; i++)
        {
            int a = in.nextInt(), b = in.nextInt();
            // a -> b
            cnt[b]++;
            if(!edges.containsKey(a))
            {
                edges.put(a, new ArrayList<>());
            }
            edges.get(a).add(b);
        }
        // 2. 拓扑排序
        Queue<Integer> q = new LinkedList<>();
        for(int i = 1; i <= n; i++)
        {
            if(cnt[i] == 0)
            {
                q.add(i);
            }
        }
        int[] ret = new int[n]; // 统计拓扑排序的结果
        int pos = 0;
        while(!q.isEmpty())
        {
            int t = q.poll();
            ret[pos++] = t;
            for(int a : edges.getOrDefault(t, new ArrayList<>()))
            {
                cnt[a]--;
                if(cnt[a] == 0)
                {
                    q.add(a);
                }
            }
        }
        if(pos == n)
        {
            // 输出结果:输出最后⼀个数的时候,不能有空格
            for(int i = 0; i < n - 1; i++)
            {
                out.print(ret[i] + " ");
            }
            out.println(ret[n - 1]);
        }
        else
        {
            out.println(-1);
        }

        out.close();
    }
}
class Read // ⾃定义快速读⼊
{
    StringTokenizer st = new StringTokenizer("");
    BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    String next() throws IOException 
    {
        while(!st.hasMoreTokens())
        {
            st = new StringTokenizer(bf.readLine());
        }
        return st.nextToken();
    }
    String nextLine() throws IOException 
    {
        return bf.readLine();
    }

    int nextInt() throws IOException 
    {
        return Integer.parseInt(next());
    }

    long nextLong() throws IOException 
    {
        return Long.parseLong(next());
    }

    double nextDouble() throws IOException 
    {
        return Double.parseDouble(next());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GR鲸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值