[编程题]: 需求生成树(2021网易校招真题)
[编程题]: 需求生成树
题目
牛牛最近在研究运送货物的问题
有一张n个点m条边无向图,每条边有一个权值。
牛牛希望构造一棵生成树(即仅保留n - 1条边,但保持图连通),使得最大边权减去最小边权的值最小。
牛牛希望你告诉他最小的这样的值是多少。
输入描述:
第一行输入两个整数n, m,表示结点数目和边的个数。
随后m行,每行输出三个整数u、v、w,表示有一条边连接u和v,边权为w。
1 <= n <= 1000, n - 1 <= m <= 3000, 1 <= w <= 10^9
数据保证初始图连通。
输出描述:
一行一个整数表示答案
示例1
输入 3 5 1 2 10 1 3 5 3 1 12 2 3 19 1 2 17 输出 2 说明 选择边权1和3,最大权值和最小权值之差为12 - 10 = 2
解题思路:
刚看到生成树只记得个最小生成树,记得有一个Prim算法和Kruskal算法用来计算图的最小生成树。但直到考试结束都不知道怎么用最小生成树来解题。
考完后想了想其实就是个 DFS 搜索,每条边两种选择:要么选这条边构成生成树;要么不选这条边构成生成树。
当边的个数达到 n - 1时,就满足了生成树的定义,就是这个图的一个生成树。在搜索的过程中,用两个变量记录下这棵生成树的最大权值和最小权值,当得到一颗生成树时,用最大值减去最小值,若比res小则更新res.
代码如下.
(不知道时间复杂度怎么样,也没OJ来测试,以前遇到的DFS经常超时,欢迎大佬指教)
Java
import java.util.Scanner; public class Main{ // 类似Kruskal算法 // 并查集用来将所有结点分块,能够被选中的边连接起来的结点属于同一个连通块(即属于一个集合) private static int[] father = null; private static boolean[] visited = null; // 仅仅用于打印由哪些边构成生成树 private static int minWeight = Integer.MAX_VALUE; // 记录生成树中权值最大的边的权值 private static int maxWeight = Integer.MIN_VALUE; // 记录生成树中权值最小的边的权值 private static int res = Integer.MAX_VALUE; // 记录生成树中最大权值边的权值与最小权值边的权值之差的最小值 public static void main(String[] args) { Scanner input = new Scanner(System.in); int n = input.nextInt(); int m = input.nextInt(); Edge[] edges = new Edge[m]; int u, v, w; for (int i = 0; i < m; i++) { u = input.nextInt(); v = input.nextInt(); w = input.nextInt(); edges[i] = new Edge(u, v, w); } father = new int[n + 1]; for (int i = 0; i <= n; i++) { father[i] = i; } visited = new boolean[m]; helper(edges, n, m, 0, 0); System.out.println(res); } // DFS搜索所有的边 // 要么不选当前边 // 要么选当前边,若要选择当前边则必须满足当前边的两个顶点分别属于不同的连通块 private static void helper(Edge[] edges, int n, int m, int index, int numEdges) { if (numEdges == n - 1) { res = Math.min(res, maxWeight - minWeight); System.out.println("-----------选择如下边构成生成树--------------"); for (int i = 0; i < m; i++) { if (visited[i]) { System.out.print(edges[i].u + " " + edges[i].v + " " + edges[i].w + "\n"); } } return; } if (index == m) { return; } else { int u = edges[index].u; int v = edges[index].v; //选这条边,则必须满足这条边的两个顶点属于不同的连通块 int faU = findFather(edges[index].u); int faV = findFather(edges[index].v); if (faU != faV) { //两个顶点分别属于不同的连通块 int oldMaxWeight = maxWeight; // 记录原来的最大权值,以便退出当前边时恢复为原来的最大权值 int oldMinWeight = minWeight; // 记录原来的最小权值,以便退出当前边时恢复为原来的最小权值 maxWeight = Math.max(maxWeight, edges[index].w); minWeight = Math.min(minWeight, edges[index].w); father[faU] = faV; // 将这条新的边两个顶点所在的连通块连接在一起(即两个对应的集合合并) visited[index] = true; // 标记当前边被用来构成生成树 helper(edges, n, m, index + 1, numEdges + 1); maxWeight = oldMaxWeight; // 退出当前边前恢复为原来的值 minWeight = oldMinWeight; // 退出当前边前恢复为原来的值 father[faU] = faU; // 退出当前边前将已经合并的集合分类成原来的 visited[index] = false; // 退出当前边前标记不用该边来构成生成树 } //不选这条边 helper(edges, n, m, index + 1, numEdges); } } private static int findFather(int x) { while (x != father[x]) { x = father[x]; } return x; } static class Edge{ int u, v, w; public Edge(int u, int v, int w) { this.u = u; this.v = v; this.w = w; } } }
输出
-----------选择如下边构成生成树-------------- 2 3 19 1 2 17 -----------选择如下边构成生成树-------------- 3 1 12 1 2 17 -----------选择如下边构成生成树-------------- 3 1 12 2 3 19 -----------选择如下边构成生成树-------------- 1 3 5 1 2 17 -----------选择如下边构成生成树-------------- 1 3 5 2 3 19 -----------选择如下边构成生成树-------------- 1 2 10 2 3 19 -----------选择如下边构成生成树-------------- 1 2 10 3 1 12 -----------选择如下边构成生成树-------------- 1 2 10 1 3 5 2
C++
#include <iostream> #include <vector> #include <algorithm> using namespace std; int maxWeight = INT_MIN; int minWeight = INT_MAX; int res = INT_MAX; vector<int> father; vector<bool> visit; struct Edge{ int u, v, w; Edge(int _u, int _v, int _w): u(_u), v(_v), w(_w){} }; // (不能压缩路径,否则返回时将出错) int findFather(int x) { while (x != father[x]) x = father[x]; return x; } void helper(vector<Edge*>& edges, int n, int m, int index, int numEdges) { if (numEdges == n - 1) { res = min(res, maxWeight - minWeight); cout << "---------选择如下边构成生成树---------" << endl; for (int i = 0; i < m; i++) { if (visit[i]) { cout << edges[i]->u << " " << edges[i]->v << " " << edges[i]->w << endl; } } return; } if (index == m) return; else { int faU = findFather(edges[index]->u); int faV = findFather(edges[index]->v); if (faU != faV) { int oldMaxWeight = maxWeight; int oldMinWeight = minWeight; maxWeight = max(maxWeight, edges[index]->w); minWeight = min(minWeight, edges[index]->w); father[edges[index]->u] = faV; visit[index] = true; helper(edges, n, m, index + 1, numEdges + 1); maxWeight = oldMaxWeight; minWeight = oldMinWeight; father[edges[index]->u] = faU; visit[index] = false; } helper(edges, n, m, index + 1, numEdges); } } int main() { int n, m; cin >> n >> m; vector<Edge*> edges; int u, v, w; for (int i = 0; i < m; i++) { cin >> u >> v >> w; edges.push_back(new Edge(u, v, w)); } for (int i = 0; i < n; i++) father.push_back(i); for (int i = 0; i < m; i++) visit.push_back(false); helper(edges, n, m, 0, 0); cout << res << endl; return 0; }
---------选择如下边构成生成树--------- 2 3 19 1 2 17 ---------选择如下边构成生成树--------- 3 1 12 1 2 17 ---------选择如下边构成生成树--------- 3 1 12 2 3 19 ---------选择如下边构成生成树--------- 1 3 5 1 2 17 ---------选择如下边构成生成树--------- 1 3 5 2 3 19 ---------选择如下边构成生成树--------- 1 2 10 2 3 19 ---------选择如下边构成生成树--------- 1 2 10 3 1 12 ---------选择如下边构成生成树--------- 1 2 10 1 3 5 2
如下的图:
输入 6 10 0 1 4 1 2 1 2 3 6 3 4 5 4 0 1 0 5 2 1 5 3 2 5 5 3 5 4 4 5 3 输出 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 3 4 5 0 5 2 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 3 4 5 1 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 3 4 5 2 5 5 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 3 4 5 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 3 4 5 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 4 0 1 0 5 2 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 4 0 1 1 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 4 0 1 2 5 5 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 4 0 1 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 4 0 1 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 0 5 2 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 1 5 3 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 3 6 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 3 4 5 4 0 1 0 5 2 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 3 4 5 4 0 1 1 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 3 4 5 4 0 1 2 5 5 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 3 4 5 4 0 1 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 3 4 5 4 0 1 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 3 4 5 0 5 2 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 3 4 5 0 5 2 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 3 4 5 1 5 3 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 3 4 5 1 5 3 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 3 4 5 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 3 4 5 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 4 0 1 0 5 2 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 4 0 1 1 5 3 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 4 0 1 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 4 0 1 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 0 5 2 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 1 5 3 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 2 1 2 5 5 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 3 4 5 4 0 1 0 5 2 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 3 4 5 4 0 1 1 5 3 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 3 4 5 4 0 1 2 5 5 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 3 4 5 4 0 1 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 3 4 5 4 0 1 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 3 4 5 0 5 2 2 5 5 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 3 4 5 0 5 2 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 3 4 5 0 5 2 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 3 4 5 1 5 3 2 5 5 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 3 4 5 1 5 3 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 3 4 5 1 5 3 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 4 0 1 0 5 2 2 5 5 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 4 0 1 0 5 2 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 4 0 1 1 5 3 2 5 5 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 4 0 1 1 5 3 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 4 0 1 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 4 0 1 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 0 5 2 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 0 5 2 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 1 5 3 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 2 3 6 1 5 3 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 3 4 5 4 0 1 0 5 2 2 5 5 -----------选择如下边构成生成树-------------- 0 1 4 3 4 5 4 0 1 1 5 3 2 5 5 -----------选择如下边构成生成树-------------- 0 1 4 3 4 5 4 0 1 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 3 4 5 4 0 1 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 3 4 5 0 5 2 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 3 4 5 0 5 2 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 3 4 5 1 5 3 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 3 4 5 1 5 3 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 4 0 1 0 5 2 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 4 0 1 1 5 3 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 0 1 4 4 0 1 2 5 5 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 0 5 2 2 5 5 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 0 1 4 1 5 3 2 5 5 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 3 4 5 4 0 1 0 5 2 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 3 4 5 4 0 1 1 5 3 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 3 4 5 4 0 1 2 5 5 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 3 4 5 4 0 1 3 5 4 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 3 4 5 4 0 1 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 3 4 5 0 5 2 1 5 3 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 3 4 5 0 5 2 2 5 5 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 3 4 5 0 5 2 3 5 4 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 3 4 5 0 5 2 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 4 0 1 0 5 2 1 5 3 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 4 0 1 0 5 2 2 5 5 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 4 0 1 0 5 2 3 5 4 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 4 0 1 1 5 3 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 4 0 1 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 4 0 1 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 0 5 2 1 5 3 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 0 5 2 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 2 3 6 0 5 2 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 3 4 5 4 0 1 0 5 2 1 5 3 -----------选择如下边构成生成树-------------- 1 2 1 3 4 5 4 0 1 0 5 2 2 5 5 -----------选择如下边构成生成树-------------- 1 2 1 3 4 5 4 0 1 1 5 3 3 5 4 -----------选择如下边构成生成树-------------- 1 2 1 3 4 5 4 0 1 1 5 3 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 3 4 5 4 0 1 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 1 2 1 3 4 5 4 0 1 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 3 4 5 0 5 2 1 5 3 3 5 4 -----------选择如下边构成生成树-------------- 1 2 1 3 4 5 0 5 2 1 5 3 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 3 4 5 0 5 2 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 1 2 1 3 4 5 0 5 2 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 4 0 1 0 5 2 1 5 3 3 5 4 -----------选择如下边构成生成树-------------- 1 2 1 4 0 1 0 5 2 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 1 2 1 4 0 1 1 5 3 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 4 0 1 2 5 5 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 0 5 2 1 5 3 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 1 2 1 0 5 2 2 5 5 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 2 3 6 3 4 5 4 0 1 0 5 2 1 5 3 -----------选择如下边构成生成树-------------- 2 3 6 3 4 5 4 0 1 1 5 3 2 5 5 -----------选择如下边构成生成树-------------- 2 3 6 3 4 5 4 0 1 1 5 3 3 5 4 -----------选择如下边构成生成树-------------- 2 3 6 3 4 5 4 0 1 1 5 3 4 5 3 -----------选择如下边构成生成树-------------- 2 3 6 3 4 5 0 5 2 1 5 3 2 5 5 -----------选择如下边构成生成树-------------- 2 3 6 3 4 5 0 5 2 1 5 3 3 5 4 -----------选择如下边构成生成树-------------- 2 3 6 3 4 5 0 5 2 1 5 3 4 5 3 -----------选择如下边构成生成树-------------- 2 3 6 4 0 1 0 5 2 1 5 3 2 5 5 -----------选择如下边构成生成树-------------- 2 3 6 4 0 1 0 5 2 1 5 3 3 5 4 -----------选择如下边构成生成树-------------- 2 3 6 4 0 1 1 5 3 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 2 3 6 4 0 1 1 5 3 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 2 3 6 0 5 2 1 5 3 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 2 3 6 0 5 2 1 5 3 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 3 4 5 4 0 1 0 5 2 1 5 3 2 5 5 -----------选择如下边构成生成树-------------- 3 4 5 4 0 1 1 5 3 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 3 4 5 4 0 1 1 5 3 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 3 4 5 0 5 2 1 5 3 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 3 4 5 0 5 2 1 5 3 2 5 5 4 5 3 -----------选择如下边构成生成树-------------- 4 0 1 0 5 2 1 5 3 2 5 5 3 5 4 -----------选择如下边构成生成树-------------- 4 0 1 1 5 3 2 5 5 3 5 4 4 5 3 -----------选择如下边构成生成树-------------- 0 5 2 1 5 3 2 5 5 3 5 4 4 5 3 2