Codeforces 1076D Edge Deletion(最短路树)
题目链接:Edge Deletion
题意:给定一张n个顶点,m条边的带权无向图,已知从顶点1到各个顶点的最短路径为di,现要求保留最多k条边,使得从顶点1到各个顶点的最短距离为di的顶点最多。输出m条边中需要保留的边的编号。
题解:先跑一遍最短路,在松弛操作时,存父子关系和边,在以这些关系建立新图(树),因为在松弛操作时存的关系,所以能保证是最短路径,最后DFS输出k条边即可。
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 typedef long long ll; 7 const int N=3e5+10; 8 9 struct qnode{ 10 ll v,w; 11 qnode(){} 12 qnode(ll v,ll w):v(v),w(w){} 13 bool operator < (const qnode& b) const{ 14 return w>b.w; 15 } 16 }; 17 18 struct node{ 19 ll nxt,v,w; 20 node(){} 21 node(ll nxt,ll v,ll w):nxt(nxt),v(v),w(w){} 22 }; 23 24 ll n,m,k,tot; 25 node edge[N<<1]; 26 ll head[N],d[N]; 27 qnode cur,tmp; 28 bool vis[N]; 29 priority_queue <qnode> Q; 30 pair <ll,ll> fa[N]; 31 vector <int> g[N],ans; 32 33 void add_edge(ll u,ll v,ll w){ 34 edge[tot]=node(head[u],v,w); 35 head[u]=tot++; 36 } 37 38 void init(){ 39 tot=1; 40 memset(head,0,sizeof(head)); 41 } 42 43 void dijkstra(ll s){ 44 for(int i=0;i<N;i++) d[i]=1e18; 45 d[s]=0; 46 Q.push(qnode(s,0)); 47 while(!Q.empty()){ 48 cur=Q.top(); 49 Q.pop(); 50 ll u=cur.v; 51 if(vis[u]) continue; 52 vis[u]=true; 53 for(ll i=head[u];i;i=edge[i].nxt){ 54 ll v=edge[i].v; 55 ll w=edge[i].w; 56 if(d[u]+w<d[v]){ 57 d[v]=d[u]+w; 58 fa[v]=make_pair(u,(i+1)/2); 59 Q.push(qnode(v,d[v])); 60 } 61 } 62 } 63 } 64 65 void dfs(int u){ 66 if(k==0) return; 67 if(u!=1){ 68 ans.push_back(fa[u].second); 69 k--; 70 } 71 for(ll v:g[u]) dfs(v); 72 } 73 74 int main(){ 75 init(); 76 scanf("%lld%lld%lld",&n,&m,&k); 77 for(ll i=1;i<=m;i++){ 78 ll u,v,w; 79 scanf("%lld%lld%lld",&u,&v,&w); 80 add_edge(u,v,w); 81 add_edge(v,u,w); 82 } 83 dijkstra(1); 84 for(ll i=2;i<=n;i++) g[fa[i].first].push_back(i); 85 dfs(1); 86 printf("%d\n",ans.size()); 87 for(ll u:ans) printf("%lld ",u); 88 printf("\n"); 89 return 0; 90 }