传球游戏
难度:简单
知识点:图论、度数统计、无向图
时间复杂度: O(n + m)
空间复杂度: O(n)
一、题目描述
小明正在和朋友们一起玩传球游戏。
游戏可以抽象成一个包含 n 个节点、m 条边的无向图,每个人恰好占据一个节点。
每条边都有一个边权 w,表示两个节点之间的距离。
传球需要遵守以下规则:
- 每个人只能将球传给与自己直接相连,且距离不超过
k的人。 - 除第一个人外,每个人都不能将球传回给刚刚传球给自己的人。
- 当某个人无法继续传球时,游戏结束。
现在,假设球最开始可以交给任意一个人,求:
- 游戏最终可能在哪些节点结束?
- 这些节点共有多少个?
输出所有可能结束游戏的节点编号,按照从小到大的顺序排列。
二、输入格式
第一行输入三个整数:
text
n m k
分别表示:
n:节点数量m:边的数量k:传球的最大距离限制
接下来 m 行,每行输入三个整数:
text
u v w
表示节点 u 和节点 v 之间存在一条权值为 w 的无向边。
数据范围:
- 1≤n,m≤1061 \le n,m \le 10^61≤n,m≤106
- 1≤k,w≤1091 \le k,w \le 10^91≤k,w≤109
- 保证图中没有重边和自环。
三、输出格式
第一行输出一个整数,表示所有可能成为游戏终点的节点数量。
第二行按照从小到大的顺序输出这些节点的编号,编号之间用空格分隔。
四、样例
样例输入
text
4 3 4
1 2 3
1 3 5
2 3 4
样例输出
text
3
1 3 4
样例解释
由于限制 k=4k=4k=4,只有边权不超过 4 的边可以传球。
因此:
- 边
1 <-> 2,权值为 3,可以传球。 - 边
1 <-> 3,权值为 5,不能传球。 - 边
2 <-> 3,权值为 4,可以传球。 - 节点 4 没有任何边,无法传球。
筛选后的有效图如下:
text
1 ----- 2 ----- 3
4
此时:
- 节点 1 的有效度数为 1。
- 节点 2 的有效度数为 2。
- 节点 3 的有效度数为 1。
- 节点 4 的有效度数为 0。
节点 1 和 3 只有一个可以传球的邻居,如果球从这个邻居传过来,就无法继续传球。
节点 4 没有任何可以传球的邻居,游戏可以直接在该节点结束。
节点 2 有两个可以传球的邻居,无论从哪个邻居接球,都可以继续传给另一个邻居。
因此答案为:
text
1 3 4
共 3 个节点。
五、解题思路
1. 核心思想
统计每个节点的有效度数。
在无向图中,节点的度数表示与该节点相连的边的数量。
但本题有一个特殊限制:
只有边权满足
w≤k w \le k w≤k
的边才能用于传球。
因此,我们只需要统计满足条件的边所形成的图中,每个节点的度数。
定义:
degi degi degi
表示节点 i 的有效度数。
2. 分类讨论
对于任意节点 i,根据有效度数可以分为三种情况。
情况一:degi=0degi=0degi=0
该节点没有任何可以传球的邻居。
如果游戏从该节点开始,就无法继续传球。
因此,该节点可以成为游戏终点。
情况二:degi=1degi=1degi=1
该节点只有一个可以传球的邻居。
如果球从这个唯一的邻居传过来,由于不能将球传回给刚刚传球的人,因此无法继续传球。
所以,该节点也可以成为游戏终点。
情况三:degi≥2degi\ge 2degi≥2
该节点至少有两个可以传球的邻居。
当球从某个邻居传过来时,即使不能将球传回原来的节点,仍然至少存在另一个邻居可以接球。
因此,该节点不可能成为游戏终点。
3. 得出结论
一个节点能够成为游戏终点,当且仅当:
degi≤1 \boxed{degi\le 1} degi≤1
因此,我们只需要:
- 遍历所有边。
- 如果边权
w <= k,则将两个端点的有效度数加一。 - 遍历所有节点,找出有效度数小于等于 1 的节点。
- 按照编号从小到大的顺序输出结果。
注意:本题不需要 BFS 或 DFS,只需要统计度数即可。
六、C++ 代码(ACM 模式)
cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
long long k;
cin >> n >> m >> k;
// 统计每个节点的有效度数
vector<int> deg(n + 1, 0);
// 读入所有边
for (int i = 0; i < m; i++) {
int u, v;
long long w;
cin >> u >> v >> w;
// 只有边权不超过 k 的边才能传球
if (w <= k) {
deg[u]++;
deg[v]++;
}
}
vector<int> ans;
// 找到所有可能成为游戏终点的节点
for (int i = 1; i <= n; i++) {
if (deg[i] <= 1) {
ans.push_back(i);
}
}
// 输出终点数量
cout << ans.size() << '\n';
// 按照编号从小到大输出
for (int i = 0; i < (int)ans.size(); i++) {
if (i > 0) cout << ' ';
cout << ans[i];
}
cout << '\n';
return 0;
}
七、复杂度分析
设图中有 n 个节点、m 条边。
时间复杂度
- 遍历
m条边,统计有效度数,时间复杂度为 O(m)O(m)O(m)。 - 遍历
n个节点,筛选答案,时间复杂度为 O(n)O(n)O(n)。 - 输出答案,最坏需要 O(n)O(n)O(n) 的时间。
因此,总时间复杂度为:
O(n+m) \boxed{O(n+m)} O(n+m)
空间复杂度
算法使用:
- 长度为
n + 1的度数数组deg,空间复杂度为 O(n)O(n)O(n)。 - 最多存储
n个答案的数组ans,空间复杂度为 O(n)O(n)O(n)。
因此,总空间复杂度为:
O(n) \boxed{O(n)} O(n)
无需存储邻接表,也无需额外排序,因为我们已经按照编号从小到大遍历节点。
八、总结
这道题的关键在于将传球规则转化为图论中的度数条件。
虽然题目描述的是一个不断传球的过程,但实际上并不需要模拟过程,也不需要搜索每个起点。
只需要筛选满足 w≤kw\le kw≤k 的边,并统计每个节点的有效度数。
最终找出满足:
degi=0或degi=1 \boxed{degi=0 \quad \text{或} \quad degi=1} degi=0或degi=1
的所有节点即可。
核心结论:
在满足边权限制的无向图中,所有有效度数不超过 1 的节点,都是可能的游戏终点。
这是一道典型的 图论建模 + 度数统计 题目。