题解 CF1076D 【Edge Deletion】

Hexarhy

2021-05-14 22:06:50

Solution

### Preface 最短路径树 SPT 练习题,难度相当于模板。 ### Solution 读题发现有删边后最短路不变的性质,暗示我们求 SPT,于是我们把这个 SPT 建出来。 SPT 上每个点到节点 $1$ 都是最短路径,经过的边都是对最短路有贡献的,剩下的边都可以删。因此 SPT 上的边便是最优方案。 同时,从节点 $1$ 出发,对这个 SPT 遍历 $\min\{k,n-1\}$ 条边,记录边的编号输出即可。这样也能保证图的连通。 ### Code ```cpp // Problem: CF1076D Edge Deletion // Contest: Luogu // URL: https://www.luogu.com.cn/problem/CF1076D // Memory Limit: 250 MB // Time Limit: 2500 ms // Author: Hexarhy // // Powered by CP Editor (https://cpeditor.org) typedef long long ll;//开 ll typedef const int cint; cint MAXN=3e5+5; int n,m,k,sum; struct node { int to;ll val;int id; bool operator<(const node& a)const { return val>a.val; } }; vector<node> edge[MAXN]; vector<int> ans; struct Edge { int u,v;ll w; }e[MAXN]; ll dis[MAXN]; int pre[MAXN]; bool visit[MAXN]; void dijkstra(void) { priority_queue<node> q; for(int i=1;i<=n;i++) dis[i]=LLONG_MAX; dis[1]=0; q.emplace(node{1,0,0}); while(!q.empty()) { cint u=q.top().to;q.pop(); if(visit[u]) continue; visit[u]=true; for(const auto& it:edge[u]) { cint v=it.to,w=it.val,id=it.id; if(dis[v]>=dis[u]+w) { if(dis[v]>dis[u]+w || e[pre[v]].w>w) pre[v]=id;//习惯了求最小最短路径树 MSPT if(dis[v]>dis[u]+w) { dis[v]=dis[u]+w; q.emplace(node{v,dis[v],0}); } } } } } void dfs(cint cur,cint fa) { if(sum>=k) return; visit[cur]=true; for(const auto& it:edge[cur]) { cint v=it.to,id=it.id; if(visit[v]) continue; if(pre[v]==id) { ans.emplace_back(id); ++sum; dfs(v,cur); if(sum>=k) return;//注意回溯时要判断是否已经达到 k } } } int main() { read(n,m,k); for(int i=1;i<=m;i++) { int u,v;ll w;read(u,v,w); e[i]=Edge{u,v,w}; edge[u].emplace_back(node{v,w,i}); edge[v].emplace_back(node{u,w,i}); } dijkstra(); memset(visit,false,sizeof(visit)); dfs(1,0); cout<<min(n-1,k)<<endl; for(const auto& Ans:ans) cout<<Ans<<' '; return 0; } ```