Codeforces 796D
题意:有一些特殊点,要求所有点距离特殊点的距离不能超过$k$,问你最多能去掉几条边。
考虑多源 BFS ,将每个特殊点初始加入 BFS 队列。由于 BFS 特殊性质,步长为1的 BFS 找到的都是最短路径。所以每个点第一次被找到都是离特殊点的最短距离。所以如果当前一条边,点已经被访问,且这条边还没被访问,这条边可以被删除。
知识点:
这道题的多源 BFS思路类似CF 987D,都是多源然后找其他点。并且这道题不仅仅可以对点进行标记,也可以对边进行标记,与欧拉回路的寻找类似。
DFS 和 BFS 慎重选择,步长为1的 BFS 有最短路的特性
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
using namespace std;
const int MAXN = 300000 + 5;
vector<int> G[MAXN];
vector<int> bh[MAXN];
queue<int> q;
int n, k, d, vis[MAXN], ans, whw[MAXN], ve[MAXN];
inline void ins(int id, int x, int y) {
G[x].push_back(y), G[y].push_back(x);
bh[x].push_back(id), bh[y].push_back(id);
}
void clean() {
ans = 0, ms(ve, 0), ms(vis, 0);
}
int solve() {
clean();
scanf("%d%d%d", &n, &k, &d);
for (int x, i = 1; i <= k; i++) scanf("%d", &x), q.push(x), vis[x] = 1;
for (int u, v, i = 1; i < n; i++) scanf("%d%d", &u, &v), ins(i, u, v);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = 0; i < (int)G[u].size(); i++) {
int v = G[u][i];
if (!vis[v]) vis[v] = 1, q.push(v); else {
if (!ve[bh[u][i]]) whw[++ans] = bh[u][i];
}
ve[bh[u][i]] = 1;
}
}
printf("%d\n", ans);
for (int i = 1; i <= ans; i++) printf("%d ", whw[i]);
return 0;
}
int main() {
solve();
return 0;
}