链接:https://codeforces.com/problemset/problem/1076/D
题意:给你一个有n个顶点、m条边的无向带权图。需要删除一些边使得剩余的边数不超过k,如果一个点在原始图到顶点1的最短距离为d,在删边后的图中到顶点的最短距离仍是d,则称这种点是 good。问如何删边,使得 good点最多。
题解:dijkstra记录最短路径,在bfs在最短路径树上搜索一个大小为k的连通块即可。
#include <bits/stdc++.h> #define IO_read ios::sync_with_stdio(false);cin.tie(0) #define fre freopen("in.txt", "r", stdin) #define _for(i,a,b) for(int i=a; i< b; i++) #define _rep(i,a,b) for(int i=a; i<=b; i++) using namespace std; typedef long long ll; const int maxn=3e5+5; const long long inf_ll= (ll)1<<61; struct qnode{ int v; ll c; qnode(int _v=0, ll _c=0):v(_v), c(_c) {} bool operator <(const qnode &r) const{ return c>r.c; } }; struct Edge{ int v; ll cost; int id; Edge(int _v=0, ll _cost=0, int _id=0): v(_v), cost(_cost), id(_id) {} }; vector<Edge> E[maxn*2]; bool vis[maxn]; ll dis[maxn]; int pre[maxn]; void dijkstra(int n, int start) { memset(vis, 0, sizeof(vis)); for(int i=1; i<=n; i++) dis[i]=inf_ll; priority_queue<qnode> que; que.push(qnode(start, 0)); dis[start]=0; while(!que.empty()) { qnode tmp=que.top(); que.pop(); int u=tmp.v; if(vis[u]) continue; vis[u]=true; for(int i=0; i<E[u].size(); i++) { int v=E[u][i].v; ll cost=E[u][i].cost; if(!vis[v] && dis[v]>dis[u]+cost) { dis[v]=dis[u]+cost; pre[v]=u; que.push(qnode(v, dis[v])); } } } } vector<int> ans; void bfs(int k, int start) { if(k==0) return; queue<int> que; que.push(start); while(!que.empty()) { int u=que.front(); que.pop(); for(int i=0; i<E[u].size(); i++) { int v=E[u][i].v; if(pre[v]==u){ que.push(v); ans.push_back(E[u][i].id/2); if(ans.size()==k) return; } } } } int main() { IO_read; //fre; int n, m, k; cin>>n>>m>>k; _rep(i, 1, m) { int u, v; long long w; cin>>u>>v>>w; E[u].push_back(Edge(v, w, i*2)); E[v].push_back(Edge(u, w, i*2+1)); } dijkstra(n, 1); bfs(k, 1); cout<<ans.size()<<"\n"; _for(i, 0, ans.size()) cout<<ans[i]<<" "; return 0; }