编程之美热身赛 题目3 : 树上的三角形

本文探讨了一种有趣的算法挑战——判断树上的边能否构成三角形。通过对树状结构的遍历与路径查找,实现了对任意两点间路径上的边长进行评估,以确定这些边长是否满足构成三角形的条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目3 : 树上的三角形

时间限制:4000ms
单点时限:2000ms
内存限制:256MB

描述

有一棵树,树上有只毛毛虫。它在这棵树上生活了很久,对它的构造了如指掌。所以它在树上从来都是走最短路,不会绕路。它还还特别喜欢三角形,所以当它在树上爬来爬去的时候总会在想,如果把刚才爬过的那几根树枝/树干锯下来,能不能从中选三根出来拼成一个三角形呢?

输入

输入数据的第一行包含一个整数 T,表示数据组数。
接下来有 T 组数据,每组数据中:
第一行包含一个整数 N,表示树上节点的个数(从 1 到 N 标号)。
接下来的 N-1 行包含三个整数 a, b, len,表示有一根长度为 len 的树枝/树干在节点 a 和节点 b 之间。
接下来一行包含一个整数 M,表示询问数。
接下来M行每行两个整数 S, T,表示毛毛虫从 S 爬行到了 T,询问这段路程中的树枝/树干是否能拼成三角形。

1 ≤ T ≤ 5
小数据:1 ≤ N ≤ 100, 1 ≤ M ≤ 100, 1 ≤ len ≤ 10000
大数据:1 ≤ N ≤ 100000, 1 ≤ M ≤ 100000, 1 ≤ len ≤ 1000000000

输出

对于每组数据,先输出一行"Case #X:",其中X为数据组数编号,从 1 开始。
接下来对于每个询问输出一行,包含"Yes"或“No”,表示是否可以拼成三角形。

样例输入
2
5
1 2 5
1 3 20
2 4 30
4 5 15
2
3 4
3 5
5
1 4 32
2 3 100
3 5 45
4 5 60
2
1 4
1 3
样例输出
Case #1:
No
Yes
Case #2:
No
Yes
package TriangleOnTree;

import java.io.BufferedInputStream;
import java.util.ArrayList;
import java.util.Scanner;

public class Main {
	int[][] node;
	String[] startEnd;
	ArrayList<Integer> values;
	int visit[];
	ArrayList<Integer> stack;
	boolean b;
	public Main(int[][] node, String[] startEnd) {
		this.node = node;
		this.startEnd = startEnd;
	}

	public void calc() {
		for (int i = 0; i < startEnd.length; i++) {
			// 初始化
			visit = new int[node[0].length];
			values = new ArrayList<Integer>(node[0].length - 1);
			stack = new ArrayList<Integer>();

			int start = Integer.parseInt(startEnd[i].split(" ")[0]) - 1;
			int end = Integer.parseInt(startEnd[i].split(" ")[1]) - 1;
			this.path(start, end);

//			System.out.println(i + ":");
//			for (Integer v : values) {
//				System.out.println(v);
//			}

			this.isTriangle();

		}
	}

	public void isTriangle() {
		boolean flag = false;
		int n = values.size();
		if (n >= 3) {
			A: for (int i = 0; i < n - 2; i++) {
				for (int j = i + 1; j < n - 1; j++) {
					for (int k = j + 1; k < n; k++) {
						int a = pd(values.get(i), values.get(j), values.get(k));
						int b = pd(values.get(i), values.get(k), values.get(j));
						int c = pd(values.get(j), values.get(k), values.get(i));
						int tmp = a + b + c;
						if (tmp == 3) {
							flag = true;
							break A;
						}
					}
				}
			}
		}
		if (flag)
			System.out.println("Yes");
		else
			System.out.println("No");
	}

	int pd(int a, int b, int c) {
		int k = a + b;
		if (k > c)
			return 1;
		else
			return 0;
	}

	public void path(int start, int end) {

		for (int j = 0; j < node[start].length; j++) {
			b = false;
			// System.out.println("node["+start+"]["+j+"]:"+node[start][j]);
			if (node[start][j] != 0 && visit[j] == 0 && visit[start] == 0) {
				visit[start] = 1;
				if (j != end) {
					values.add(node[start][j]);
					stack.add(start);
					path(j, end);
					if(b)
						return ;
				} else {
					b = true;
					values.add(node[start][j]);
					break;
				}
			} else {
				if (j == node[start].length - 1) {
					visit[start] = 1;
					visit[stack.get(stack.size() - 1)] = 0;
					stack.remove(stack.size() - 1);
					values.remove(values.size() - 1);
				}
			}
		}
	}

	public static void main(String[] args) {
		Scanner cin = new Scanner(new BufferedInputStream(System.in));

		// 数据组数
		int num = cin.nextInt();
		cin.nextLine();

		for (int i = 0; i < num; i++) {
			// 节点个数
			int NodeNum = cin.nextInt();
			int[][] node = new int[NodeNum][NodeNum];
			cin.nextLine();
			for (int j = 1; j < NodeNum; j++) {
				int start = cin.nextInt();
				int end = cin.nextInt();
				int value = cin.nextInt();
				// System.out.println("node["+ (start-1) +"]["+ (end-1)
				// +"]:"+value);
				cin.nextLine();
				// System.out.println(start);
				// System.out.println(end);
				node[start - 1][end - 1] = value;
				node[end - 1][start - 1] = value;
			}
			int TestNum = cin.nextInt();
			cin.nextLine();
			String[] startEnd = new String[TestNum];
			for (int j = 0; j < TestNum; j++) {
				startEnd[j] = cin.nextLine();
			}
			System.out.println("Case #" + (i + 1) + ":");
			Main tot = new Main(node, startEnd);
			tot.calc();
		}
		cin.close();
	}

}

本题提交未通过,欢迎纠错!当然,我用的方法是最原始、最容易想的方法。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值