小度给定你一棵拥有n个点的树,每次删去当前所有的叶子节点(即度数小于等于1的节点)和叶子节点所连接的边,直到所有的点都被删除了为止。
你需要对于每个点,求出它是第几次操作中被删除的。
第一行一个数字,表示树上节点个数
接下来n - 1行,每行两个数字,表示树上的一条边。
一行n个数字,第i个数字表示节点i在第几次操作中被删除。
5 1 2 1 3 2 4 2 5
2 2 1 1 1
4 1 2 1 3 1 4
2 1 1 1
import java.util.ArrayList; import java.util.List; import java.util.Scanner; class Node { int num; List<Node> friend; Boolean deleted = false; public Node() { this.friend = new ArrayList<>(); } } public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); Node[] nodes = new Node[n]; for (int i = 0; i < n; i++) { nodes[i] = new Node(); } for (int i = 0; i < n - 1; i++) { int a = sc.nextInt() - 1; int b = sc.nextInt() - 1; nodes[a].friend.add(nodes[b]); nodes[b].friend.add(nodes[a]); nodes[a].num++; nodes[b].num++; } int count = 1; int[] res = new int[n]; int flag = 0; while (flag < n) { List<Node> list = new ArrayList<>(); for (int i = 0; i < nodes.length; i++) { if (nodes[i].deleted) continue; if (nodes[i].num <= 1) { nodes[i].num -= 1; res[i] = count; list.add(nodes[i]);//在一轮遍历后,统一处理被删除节点地friend的num值。如果在这里直接处理,会屏蔽掉后面 flag++; nodes[i].deleted = true; } } for (Node node : list) { for (Node aFriend : node.friend) { aFriend.num--; } } count++; } for (int re : res) { System.out.print(re + " "); } } }
C++ 模拟
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; vector<int> g[maxn]; int ans[maxn], deg[maxn], vis[maxn]; int main() { int n, u, v; cin >> n; for (int i = 1; i <= n - 1; ++i) { // 建立邻接表,统计节点度数 scanf("%d%d", &u, &v); g[u].push_back(v); g[v].push_back(u); deg[u]++, deg[v]++; } vector<int> q; // 保存的是节点度数小于等于1的节点 for (int i = 1; i <= n; ++i) if (deg[i] <= 1) q.push_back(i), vis[i] = true; int count = 0; while (!q.empty()) { count++; vector<int> tmp; // 保存新产生的度数小于等于1的节点 for (auto u : q) { ans[u] = count; for (int v : g[u]) { // 删除节点及对应的边 if (!vis[v] && --deg[v] <= 1) tmp.push_back(v), vis[v] = true; } } q = tmp; } for (int i = 1; i <= n; ++i) printf("%d ", ans[i]); return 0; }
import java.util.*; public class Main{ public static class Node{ //静态内部类 public List<Node> list= new ArrayList<>(); //树除根节点就一个父啊,是图的话就可以多个,用Node类型的list存 public int num = 0; //存节点的度,用List.size()方法更新很麻烦,remove后size和索引也变了 boolean flag = false; //节点是否删除 } public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int count = n; int time = 1; int[] res = new int[n+1]; Node[] nodes = new Node[n+1]; for(int i = 0; i < n+1; ++i){ //Node[]初始化必要 Node node = new Node(); nodes[i] = node; } while(sc.hasNext()){ //相当于 for(int i = 0; i < n-1; i++) int a = sc.nextInt(); int b = sc.nextInt(); nodes[a].list.add(nodes[b]); nodes[b].list.add(nodes[a]); //数组下标即是节点号,不用属性value了 nodes[a].num++; nodes[b].num++; } while(count > 0){ List<Node> levelNode = new ArrayList<>(); //存这次删除的节点 for( int i = 1; i < n+1; ++i){ //不能从0开始 //定义:树入度<=1(根节点是0,其他都是1),叶子节点出度=0。故叶子节点的度<=1且没有删除就该删除 if(nodes[i].num <= 1 && !nodes[i].flag){ res[i] = time; nodes[i].flag = true; levelNode.add(nodes[i]); //将被删除的节点加入链表,在后面的遍历里更新 count--; } } //将这次删除的节点的关联节点的数据更新 for(Node node : levelNode){ for(Node i : node.list) i.num--; } time++; } for( int i = 1; i < n; ++i){ System.out.print(res[i]+" "); //输出示例有空格要求 } System.out.print(res[n]); } }
import java.util.*; import java.util.Scanner; import java.lang.Math; import java.util.ArrayList; public class Main{ static int N = 200010; static int[] e, ne, h; static int[] d; static int index; public static void main(String[] args) { Scanner scan = new Scanner(System.in); int n = scan.nextInt(); e = new int[N]; ne = new int[N * 2]; h = new int[N]; d = new int[n + 1]; Arrays.fill(ne, -1); Arrays.fill(h, -1); int m = n - 1; while ((m--) > 0) { int a = scan.nextInt(); int b = scan.nextInt(); add(a, b); add(b, a); d[a]++; d[b]++; } boolean[] st = new boolean[n + 1]; int[] res = new int[n]; int[] que = new int[N]; int tail = -1; int head = 0; for (int i = 1; i <= n; i++) { if (d[i] == 1) { que[++tail] = i; st[i] = true; } } int step = 1; while (tail >= head) { int size = tail - head + 1; for (int i = 0; i < size; i++) { int cur = que[head++]; res[cur - 1] = step; for (int j = h[cur]; j != -1; j = ne[j]) { int val = e[j]; if (!st[val]) { d[val]--; if (d[val] == 1 || d[val] == 0) { que[++tail] = val; st[val] = true; } } } } ++step; } for (int i = 0; i < n; i++) { System.out.print(res[i]); if (i != n -1) System.out.print(" "); } } public static void add(int a, int b) { e[index] = b; ne[index] = h[a]; h[a] = index++; } }
#include <bits/stdc++.h> using namespace std; queue<pair<int,int>>q; vector<int>edge[100005]; int d[100005] = {0},ans[100005]; int main() { int n,u,v; cin >> n; for(int i = 1; i < n; i++) { cin >> u >> v; edge[u].push_back(v); edge[v].push_back(u); } for(int i = 1; i <= n; i++) { d[i] = edge[i].size(); if(d[i] <= 1) { q.push({i,1}); } } while(!q.empty()) { auto it = q.front(); q.pop(); ans[it.first] = it.second; for(int i = 0; i < edge[it.first].size(); i++) { d[edge[it.first][i]]--; if(d[edge[it.first][i]] == 1) { q.push({edge[it.first][i],it.second+1}); ans[edge[it.first][i]] = it.second + 1; } } } for(int i = 1; i <= n; i++) { cout << ans[i] << " "; } return 0; }
import java.util.*; public class Main{ public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[] du = new int[n + 1]; int[] visited = new int[n + 1]; LinkedList<Integer>[] edges = new LinkedList[n + 1]; for (int i = 0; i <= n; i++) { edges[i] = new LinkedList<>(); } for (int i = 1; i < n; i++) { int a = sc.nextInt(); int b = sc.nextInt(); edges[a].add(b); edges[b].add(a); du[a] ++; du[b] ++; } int del = 0; int time = 1; int[] ans = new int[n + 1]; while (del < n) { List<Integer> arr = new ArrayList<>(); for (int i = 1; i <= n; i++) { if (du[i] == 1 && visited[i] == 0) { arr.add(i); visited[i] = 1; del++; ans[i] = time; } } for (int i : arr) { for (int neighbor : edges[i]) { du[neighbor]--; } } time++; } for (int i = 1; i <= n; i++) { System.out.print(ans[i]); System.out.print(" "); } } }只能通过60%
import java.util.*; /** * @author hit-eason * @version 1.0 * @date 2021/9/6 21:39 */ public class Main{ public static class Node{ public List<Node> parents = new ArrayList<>(); //未通过的测试用例发现一个节点可以有多个父亲,故用链表存节点的父亲 public List<Node> kids = new ArrayList<>(); //尽管按照测试用例貌似一个节点只有一个儿子,但是用链表存不会错 public int outNum = 0; //另开个整型存节点出度,如果用List.size()之类方法更新很麻烦 public int inNum = 0; //节点入度 boolean flag = true; //节点是否已被删除 } public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int count = n; int storey = 1; int[] res = new int[n]; Node[] nodes = new Node[n]; //开数组存n个节点 for(int i = 0; i < n; ++i){ Node node = new Node(); nodes[i] = node; } //根据后续读入行更新节点入度出度、父节点子节点 while(sc.hasNext()){ int from = sc.nextInt(); int to = sc.nextInt(); nodes[from-1].outNum++; nodes[to-1].inNum++; nodes[from-1].kids.add(nodes[to-1]); nodes[to-1].parents.add(nodes[from-1]); } //count控制是否已删除所有节点 while(count > 0){ List<Node> levelNode = new ArrayList<>(); //存这层删除的节点,必须在for循环遍历后再去50行的levelNode遍历里更新,否则一边删一边更新会删除后面层的节点 for( int i = 0; i < n; ++i){ //入度+出度不大于1就该删除,并且用flag判断是否已删除过,防止重复给结果赋值 if((nodes[i].outNum + nodes[i].inNum) <= 1 && nodes[i].flag){ res[i] = storey; nodes[i].flag = false; levelNode.add(nodes[i]); //将被删除的节点加入链表,在后面的遍历里更新 count--; //循环结束条件更新,即剩余未删除的节点数 } } //将这层删除的节点的关联节点的数据更新 for(Node node : levelNode){ for(Node parent : node.parents) parent.outNum--; for(Node kid : node.kids) kid.inNum--; } storey++; //层数加一 } for( int i = 0; i < n-1; ++i){ System.out.print(res[i]+" "); } System.out.print(res[n-1]); } }
n = int(input()) # 初始化邻接表 edge_table = dict() for k in range(n): edge_table[k] = set() # 输入边的信息 for _ in range(n-1): u, v = [int(i)-1 for i in input().split()] edge_table[u].add(v) edge_table[v].add(u) # 找到可删除的节点 rmv_lst = set() for i, elm in edge_table.items(): if len(elm) < 2: rmv_lst.add(i) res = [0]*n next_candidate = set() for cnt in range(1, 100000): # 使用cnt记录这是第几次迭代 if len(rmv_lst) == 0: # 如果没有可删除节点,就结束循环 break next_candidate.clear() # 清空下一次可删除的节点的候选列表 for rmv in rmv_lst: for other in edge_table[rmv]: edge_table[other].remove(rmv) # 移除与被删除节点相连的边 next_candidate.add(other) # 将候选节点加入到候选列表中 res[rmv] = cnt # 记录此节点是第几次删除的 # 清空可删除节点列表,找出候选列表中可删除的节点放入可删除节点列表中 rmv_lst.clear() for cddt in next_candidate: # 还没有被删除,且边的个数小于2的节点为可删除节点 if res[cddt] == 0 and len(edge_table[cddt]) < 2: rmv_lst.add(cddt) print(" ".join(map(str, res)))