思路:删除尽量多的边使得所有点都能在限制距离之内到达一个警局,删除边会形成多棵子树,最多只能k棵。其实就是以每个警局为根结点,把整棵树划分为以警局为根结点的k棵树,说明要删除的边的数量就是k-1条,即删除的边的条数是一定的。剩下就是为每个节点找根结点,考虑从所有警局出发得到到每个点的最短距离,则当前节点u,一定是从u->v,如果d[v] <= lim则这条边一定会保留。
AC代码
#include <cstdio> #include <cmath> #include <cctype> #include <algorithm> #include <cstring> #include <utility> #include <string> #include <iostream> #include <map> #include <set> #include <vector> #include <queue> #include <stack> using namespace std; #pragma comment(linker, "/STACK:1024000000,1024000000") #define eps 1e-10 #define inf 0x3f3f3f3f #define PI pair<int, int> typedef long long LL; const int maxn = 3e5 + 5; int vis[maxn], d[maxn]; int n, k, lim; map<PI, int>ha; vector<int>G[maxn]; queue<int>q; int main() { while(scanf("%d%d%d", &n, &k, &lim) == 3) { ha.clear(); while(!q.empty()) q.pop(); for(int i = 1; i <= n; ++i) G[i].clear(); memset(d, -1, sizeof(d)); int pos; for(int i = 0; i < k; ++i) { scanf("%d", &pos); d[pos] = 0; q.push(pos); } int u, v; for(int i = 0; i < n-1; ++i) { scanf("%d%d", &u, &v); ha[make_pair(u, v)] = i+1; ha[make_pair(v, u)] = i+1; G[u].push_back(v); G[v].push_back(u); } memset(vis, 0, sizeof(vis)); int cnt = 0; //要保留的边的数量 while(!q.empty()) { int u = q.front(); q.pop(); for(int i = 0; i < G[u].size(); ++i) { int v = G[u][i]; if(d[v] == -1) { d[v] = d[u] + 1; q.push(v); if(d[v] <= lim) { int id = ha[make_pair(u, v)]; vis[id] = 1; ++cnt; } } } } printf("%d\n", n-cnt-1); //printf("%d\n", k-1); for(int i = 1; i <= n-1; ++i) { if(!vis[i]) printf("%d ", i); } printf("\n"); } return 0; }
如有不当之处欢迎指出!