【JAVA】求拓扑排序可能在第二个位置的点个数(Pro20210924)(拓扑排序)

本文介绍了一种简单的方法来解决Java编程中的拓扑排序问题,通过反向分析比赛结果,计算可能成为第二名的人数,重点在于理解入度概念并应用。题目背景涉及比赛胜负关系,实际考察的是数据结构中的拓扑排序算法应用。
摘要由CSDN通过智能技术生成

【JAVA】求拓扑排序可能在第二个位置的点个数(Pro20210924)(拓扑排序)

题目

N个人在举行一对一比拼的比赛。每个人的实力都是确定的,互不相同且不会改变。比赛的胜负总是由实力决定。因为是没有进行完所有比赛的状态,还无法准确看出谁是第一名,谁是第二名。

比如,假设知道下面一部分比赛的结果。参赛人员从1到N编号,箭头出发点上的人输给了箭头终点上的人。(胜←败)

在这里插入图片描述
[图1]

[图1]中可能成为第一的人有2,3,5,8这4名。因为第一名还没有确定,所以4个人都有可能成为第二名。如果有人只输给了2,3,5,8中的一个人,那么这个人也有可能是第二,但上图中没有这样的情况。4的情况虽然只输给了6号一个人,但6又输给了2和8,就不可能是第一名了,因此可以知道4只能是第三名以下。再看下面的情况。
在这里插入图片描述

[图2]

这个情况下可以确定8是第一名。因此8就不可能是第二了。只输给了8的1,2,6是有可能成为第二名的。

输入比赛进行的结果,编写程序,计算有可能是第二名的人的数量。

[限制条件]

  1. 人数N是2到100,000之间的整数。
  2. 比赛次数M所示0到200,000之间的整数。
  3. 一个人不能和自己进行比赛。

[输入]
第一行给出测试用例个数T。接着给出T个测试用例。每个测试用例的第一行给出人数N和比赛次数M。接下来的M行,每行给出代表一场比赛结果的2个人的编号A,B,用空格分隔。表示A赢了B。

[输出]
用标准输出按顺序输出各测试用例的答案。每个测试用例先输出"#x" (x是测试用例号码,从1开始,不要引号),然后输出一个空格后,输出有可能是第二名的人的数量。

[输入输出示例]
(输入)
3
8 7
8 1
8 6
2 1
2 6
6 4
2 7
3 7
8 10
8 1
8 6
8 2
8 4
2 5
2 7
2 3
3 7
4 3
6 4
4 3
1 2
3 4
1 2
(输出)
#1 4
#2 3
#3 4

思路

吐槽下,水题~~~
原图反向后,求拓扑排序可能在第二个位置的点个数即可(不用求拓扑排序结果,只考到了入度的概念而已)。

  1. 原图反向后求入度是0的点的个数P,若 P ==1,则该点为第一名,P重置为0;(若P > 1,则这些点都有可能是第二名,P保留);
  2. 求入度是0的点的可到达点中,入度是1的点个数Q(若入度大于1,则不可能是第二名);
  3. P + Q 即为所求。

注意点:Case中会给重复边,去重建议用Set。(List.Contains()方法为循环判断,效率太低,建议不要使用)

代码

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;

public class Main {
	static int T, N, M, ASW, IN[];
	static Set<Integer>[] DATA;

	public static void main(String[] args) throws Exception {
		System.setIn(new FileInputStream("D:\\SW\\TestCase\\sample_input_20210924.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		T = Integer.parseInt(br.readLine());

		for (int t = 1; t <= T; t++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());
			ASW = N;

			IN = new int[N + 1];
			DATA = new HashSet[N + 1];
			for (int n = 1; n <= N; n++)
				DATA[n] = new HashSet<Integer>();

			for (int a, b, m = 0; m < M; m++) {
				st = new StringTokenizer(br.readLine());
				a = Integer.parseInt(st.nextToken());
				b = Integer.parseInt(st.nextToken());

				if (DATA[a].add(b) && ++IN[b] == 1) ASW--;
			}

			if (ASW == 1) ASW = 0;

			for (int n = 1; n <= N; n++) {
				if (IN[n] > 0) continue;

				for (int next : DATA[n])
					if (IN[next] == 1) ASW++;
			}

			System.out.println(t + " " + ASW);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值