题目链接:http://codeforces.com/contest/1076/problem/D
题目大意:
一个图N个点M条双向边。设各点到点1的距离为di,保证满足条件删除M-K条边之后使得到点1的距离仍为di的点数量最多的情况下,输出剩余的K条边的编号(按输入顺序)。
(2≤n≤3⋅105, 1≤m≤3⋅105, n−1≤m, 0≤k≤m)
解题思路:太菜了没写出来。。。
参考自博客:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/9951711.html
用迪杰斯特拉在图中跑最短路,并且利用两个数组存被松弛节点的父节点和保存对应的边,然后用bfs贪心保留离源点近的边。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=3e5+5; int n,m,k; struct qnode{ int v; ll d; qnode(int a,ll b):v(a),d(b){} bool operator<(const qnode& x)const{ return d>x.d; } }; struct edge{ int id,v; ll w; edge(int a,int b,ll c):id(a),v(b),w(c){} }; vector<edge> mp[maxn]; void add(int id,int u,int v,ll w) { mp[u].push_back(edge(id,v,w)); mp[v].push_back(edge(id,u,w)); } int vis[maxn],pree[maxn],pret[maxn]; ll dis[maxn]; priority_queue<qnode> pq; void dij() { memset(vis,0,sizeof(vis)); memset(dis,0x3f3f3f3f,sizeof(dis)); dis[1]=0; pret[1]=1; pq.push(qnode(1,0)); while(!pq.empty()) { qnode q=pq.top(); pq.pop(); int u=q.v; if(vis[u]) continue; vis[u]=1; for(int i=0;i<mp[u].size();i++) { int id=mp[u][i].id; int v=mp[u][i].v; ll w=mp[u][i].w; if(!vis[v]&&dis[v]>dis[u]+w) { dis[v]=dis[u]+w; pret[v]=u; pree[v]=id; pq.push(qnode(v,dis[v])); } } } } vector<int> son[maxn]; queue<int> que; vector<int> ans; void bfs() { que.push(1); while(!que.empty()) { int u=que.front(); que.pop(); for(int i=0;i<son[u].size();i++) { int v=son[u][i]; if(k>0) { ans.push_back(pree[v]); que.push(v); k--; } else break; } } } int main() { ios_base::sync_with_stdio(false); cin.tie(0); cin>>n>>m>>k; for(int i=1;i<=m;i++) { int u,v; ll w; cin>>u>>v>>w; add(i,u,v,w); } dij(); for(int i=2;i<=n;i++) son[pret[i]].push_back(i); bfs(); cout<<ans.size()<<endl; if(ans.size()==0) return 0; cout<<ans[0]; for(int i=1;i<ans.size();i++) cout<<" "<<ans[i]; cout<<endl; return 0; }