题意:给你一个无向图,之后又n个点m条边,现在让你将整个图删成只剩下k条边,并且保证删除后的边的最短路不变,现在问你剩下的边的编号是多少
思路:删除的边要保证最短路不变,那么就可以看出,松弛的边是一定不能删除的,因为删除他之后我们的最短路肯定会改变的,那么我们将松弛的边全部找出来,取完之后我们会发现每一个前驱只可能有一个后继,那么这其实就是一棵树了,之后我们从树的根节点里选出k个点就好了。
代码:
#include <bits/stdc++.h>
using namespace std;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 3e5+10;
vector<tuple<int,long long,int> >V[maxn];
vector<int>A;
long long dis[maxn] ;
int vis[maxn] , pre[maxn];
int n , m , k , u , v , w;
struct node
{
int v;
long long num;
node (int a,long long b) :v(a),num(b){}
bool operator < (const node b) const
{
return b.num < num;
}
};
void dij(int s)
{
priority_queue<node>Q;
for(int i = 1 ; i <= n ; i ++) dis[i] = INF , vis[i] = 0,pre[i] = -1;
dis[s] = 0;
k++;
Q.push(node(s,0));
while(!Q.empty())
{
node p = Q.top(); Q.pop();
int u = p.v;
if(vis[u]) continue;
vis[u] = 1;
A.push_back(pre[u]);
k--;
if(k == 0) break;
for(int i = 0 ; i < V[u].size() ; i ++)
{
int v,id;
long long w;
tie(v,w,id) = V[u][i];
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
pre[v] = id;
Q.push(node(v,dis[v]));
}
}
}
cout<<A.size() - 1<<endl;
for(int i = 1 ; i < A.size() ; i++)
{
cout<<A[i]<<" ";
}
puts("");
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i = 0 ; i < m ; i ++)
{
scanf("%d%d%d",&u,&v,&w);
V[u].emplace_back(v,w,i+1);
V[v].emplace_back(u,w,i+1);
}
dij(1);
return 0;
}