题目大意:给定 N 个点 M 条边的无向简单联通图,留下最多 K 条边,求剩下的点里面从 1 号顶点到其余各点最短路大小等于原先最短路大小的点最多怎么构造。
这个题贪心+dijkstra
我们可以在第一次跑 dij 时直接采用贪心策略,即:若当前答案集合的大小小于 K 且优先队列非空,则继续优先队列遍历,每次把一条边加入到答案集合中。
因为是在求解最短路过程中向答案集合中加边,可知这就是一种最优策略。
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 5e5 + 5;
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
typedef pair<LL,int> pii;
struct node{
int nxt,to,w;
}e[N<<1];
int head[N],n,m,k,pre[N],vis[N],tot = 1;
inline void add(int x,int y,int w){
e[++tot] = node{head[x],y,w},head[x] = tot;
}
LL dis[N];
vector<int> ans;
priority_queue<pii> q;
void init(){
n = read(),m = read(),k = read();
for(int i = 1;i <= m;i++){
int x = read(),y = read(),w = read();
add(x,y,w),add(y,x,w);
}
}
void dij(){
for(int i = 2;i <= n;i++) dis[i] = 1e15;
q.push(make_pair(0,1));
while(!q.empty() && ans.size() < k){
int u = q.top().second;
q.pop();
if(vis[u]) continue;
if(u ^ 1) ans.push_back(pre[u] / 2);
vis[u] = 1;
for(int i = head[u];i;i = e[i].nxt){
int v = e[i].to,w = e[i].w;
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w,pre[v] = i;
q.push(make_pair(-dis[v],v));
}
}
}
}
void solve(){
dij();
k = ans.size();
printf("%d\n",k);
for(int i = 0;i < k;i++) printf("%d ",ans[i]);
}
int main(){
init();
solve();
return 0;
}