Educational Codeforces Round 54 1076D Edge Deletion(Dijkstra 最短路树)

You are given an undirected connected weighted graph consisting of nn vertices and mm edges. Let’s denote the length of the shortest path from vertex 11 to vertex ii as didi.

You have to erase some edges of the graph so that at most kk edges remain. Let’s call a vertex ii good if there still exists a path from 11 to ii with length didi 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 nn,mmand k(2n3105,1m3105,n1m,0km)k (2≤n≤3⋅10^5, 1≤m≤3⋅10^5, n−1≤m, 0≤k≤m)— the number of vertices and edges in the graph, and the maximum number of edges that can be retained in the graph, respectively.

Then mm lines follow, each containing three integers x,y,w(1x,yn,xy,1w109)x, y, w (1≤x,y≤n, x≠y, 1≤w≤10^9), denoting an edge connecting vertices xx and yy and having weight ww.

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 ee — the number of edges that should remain in the graph (0ek)(0≤e≤k).

In the second line print e distinct integers from 11 to mm — 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


题目大意:
一个有nn个顶点和mm条边,现在让你最多留下kk条边,使得到点11的距离仍为didi(意思就是删去对最短路没有贡献or贡献较小的边)的点数量最多的情况下,输出剩余的KK条边的编号

最后图中最多剩下kk条边,当然也可以比KK少.


思路:
Dijkstra+堆优化跑最短路,将过程中遇到的边标记,这样跑出来的前KK条边一定是价值最大的(同比其他边更接近树根),输出就好

需要注意的是要开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;
}
posted @ 2018-11-14 23:34  秃头大师  阅读(139)  评论(0编辑  收藏  举报