Educational Codeforces Round 54 1076D Edge Deletion(Dijkstra 最短路树)
You are given an undirected connected weighted graph consisting of vertices and edges. Let’s denote the length of the shortest path from vertex to vertex as .
You have to erase some edges of the graph so that at most edges remain. Let’s call a vertex good if there still exists a path from to with length after erasing the edges.
Your goal is to erase the edges in such a way that the number of good vertices is maximized.
Input
The first line contains three integers ,and — the number of vertices and edges in the graph, and the maximum number of edges that can be retained in the graph, respectively.
Then lines follow, each containing three integers , denoting an edge connecting vertices and and having weight .
The given graph is connected (any vertex can be reached from any other vertex) and simple (there are no self-loops, and for each unordered pair of vertices there exists at most one edge connecting these vertices).
Output
In the first line print — the number of edges that should remain in the graph .
In the second line print e distinct integers from to — the indices of edges that should remain in the graph. Edges are numbered in the same order they are given in the input. The number of good vertices should be as large as possible.
Examples
input
3 3 2
1 2 1
3 2 1
1 3 3
output
2
1 2
input
4 5 2
4 1 8
2 4 1
2 1 3
3 4 9
3 1 5
output
2
3 2
题目大意:
一个有个顶点和条边,现在让你最多留下条边,使得到点的距离仍为(意思就是删去对最短路没有贡献or贡献较小的边)的点数量最多的情况下,输出剩余的条边的编号
最后图中最多剩下条边,当然也可以比少.
思路:
用Dijkstra+堆优化跑最短路,将过程中遇到的边标记,这样跑出来的前条边一定是价值最大的(同比其他边更接近树根),输出就好
需要注意的是要开long long
和不能用SPFA(会被卡掉)
AC代码如下:
#include <map>
#include <queue>
#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <iostream>
#include <sstream>
#include <algorithm>
#define lowbit(a) (a&(-a))
#define _mid(a,b) ((a+b)/2)
#define _mem(a,b) memset(a,0,(b+3)<<2)
#define fori(a) for(ll i=0;i<a;i++)
#define forj(a) for(ll j=0;j<a;j++)
#define ifor(a) for(ll i=1;i<=a;i++)
#define jfor(a) for(ll j=1;j<=a;j++)
#define mem(a,b) memset(a,b,sizeof(a))
#define IN freopen("in.txt","r",stdin)
#define OUT freopen("out.txt","w",stdout)
#define IO do{\
ios::sync_with_stdio(false);\
cin.tie(0);\
cout.tie(0);}while(0)
#define mp(a,b) make_pair(a,b)
#define debug(a) cout <<(a) << endl
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PAIR;
const ll maxn = 1e6+9; //这里不能开3*1e5,无向图是2倍大小因为这个被卡了一次
const ll INF = 0x3f3f3f3f;
const ll inf = 0x3f;
const double EPS = 1e-7;
const double Pi = acos(-1);
const ll MOD = 1001113;
ll fir[maxn],Next[maxn],to[maxn],val[maxn],cnt;
ll fa[maxn];
ll id[maxn]; //第几条边(边的标号)
bool v[maxn];
void add(ll u,ll v,ll w,ll idx) {
Next[++cnt] = fir[u];
fir[u] = cnt;
to[cnt] = v;
val[cnt] = w;
id[cnt] = idx;
}
struct node {
ll dis,id,v;
bool operator < (const node a) const{//按照dis从小到大
return dis > a.dis;
}
};
ll dis[maxn],vis[maxn];
vector <ll >res(maxn);
void Dijkstra(ll k) {
ll cnr = 0;
mem(dis,inf);
dis[1] = 0;
priority_queue<node>q;
ll buf;
ll Max = INF;
for(ll e=fir[1];e;e = Next[e]){//找到从1开始最短的那条边的标号
if(val[e] < Max)
Max = val[e],buf = id[e];
}
v[buf] = true;
q.push({0,buf,1});
while(!q.empty()) {
node u = q.top();
q.pop();
if(vis[u.v])
continue;
vis[u.v] = true;
if(u.v!=1) {
res[cnr++] = fa[u.v]; //fa[i]代表最短路树中连接点i的边的标号
v[fa[u.v]] = true;
}
if(cnr >= k)
break;
for(ll e=fir[u.v]; e; e = Next[e]) {
ll v = to[e],w = val[e],idx = id[e];
if(!vis[v] && u.dis + w < dis[v]) {
fa[v] = idx;
dis[v] = u.dis + w;
q.push({dis[v],idx,v});
}
}
}
int x = min(k,cnr); //ans<=k
cout << x << endl;
fori(x)
cout << res[i] <<" ";
}
int main() {
//IN;
ll n,m,k;
ll u,v,w;
cin >>n >> m >> k;
ifor(m) {
cin >> u >> v>> w;
add(u,v,w,i);
add(v,u,w,i);
}
Dijkstra(k);
return 0;
}