D. Edge Deletion--Educational Codeforces Round 54 (Rated for Div. 2)(最短路树)

传送门:https://codeforces.com/contest/1076/problem/D

                                                   D. Edge Deletion

                                                                 time limit per test 2.5 seconds

                                                            memory limit per test  256 megabytes

                                                                        input   standard input

                                                                      output   standard output

You are given an undirected connected weighted graph consisting of n vertices and m edges. Let's denote the length of the shortest path from vertex 1 to vertex i as di.

You have to erase some edges of the graph so that at most k edges remain. Let's call a vertex i good if there still exists a path from 1 to i 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, mm and k (2≤n≤3⋅105, 1≤m≤3⋅105n−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 xx, yy, ww (1≤x,y≤n, x≠y, 1≤w≤109), denoting an edge connecting vertices x and y and having weight w.

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

In the second line print ee distinct integers from 1 to m — 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 

题意:给定一张图,n个节点,m条边,现要求保留其中的最多k条边,使得删边后的图中节点1到各点的最短路长度仍为删除前的最短路长度的节点数最多,求保留的边,2≤n≤300000, 1≤m≤300000, n−1≤m, 0≤k≤m;(可能描述不是很清楚,没看懂就看题目吧

 

解法:只需跑一遍dijkstra求一下节点1到各点的最短路,实际上边权为正的连通图生成的是一颗树,称之为最短路树(至于为啥是树:从dijkstra算法思想大概可以看出来吧)那么找出棵树后从根节点1跑dfs或者bfs就行了吧(:

 

附code:

#include<bits/stdc++.h>

using namespace std;

#define pii pair<int, int>
#define mem(a,b) memset(a,b,sizeof(a))
#define per(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a,b) for(int i=a;i>=b;i--)
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
typedef long long ll;

template <class T> inline void read(T &x) {
	x = 0;int f = 1;char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	x=x*f;
}
template<typename E> E gcd(E a,E b){return b==0?a:gcd(b,a%b);}
template<typename E> E ex_gcd(E a,E b,E &x,E&y) {if(b==0){x=1;y=0;}else {ex_gcd(b,a%b,y,x);y-=(a/b)*x;}}
template<typename E> E quick_pow(E a,E b,E c){E ans=1;while(b){if(b&1) ans=ans*a%c;a=a*a%c;b>>=1;}return ans;}
template<typename E> E inv1(E a,E b){return quick_pow(a,b-2,b);}
template<typename E> E inv2(E a,E b){E x,y;ex_gcd(a,b,x,y);return (x%b+b)%b;}

/*================Header Template==============*/

const double eps=1.0e-5;
const int maxn=300000+10;
const ll mod=10007;

int n,m,k,from,to,total=0;ll co; 
ll dis[maxn];
vector<pair<int,pair<ll,int> > > edge[maxn];
bool vis[maxn];
vector<pair<int,int> > vec[maxn],tree[maxn];
int ans[maxn];

void dijkstra(int s)
{
	priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > que;
	per(i,1,n) dis[i]=1e18;dis[1]=0;
	que.push(make_pair(0,s));
	while(!que.empty()){
		pair<ll,int> fron=que.top();que.pop();
		if(vis[fron.second]) continue;
		vis[fron.second]=true;
		for(int i=0;i<edge[fron.second].size();i++){
			int to=edge[fron.second][i].first,w=edge[fron.second][i].second.first;
			if(dis[to]>dis[fron.second]+w){
				dis[to]=dis[fron.second]+w;
				que.push(make_pair(dis[to],to));
				vec[to].clear();
				vec[to].push_back(make_pair(fron.second,edge[fron.second][i].second.second));
			}
		}
	}
}

int main()
{
	scanf("%d%d%d",&n,&m,&k);mem(vis,false);
	per(i,1,m){
		read(from);read(to);read(co);
		edge[from].push_back(make_pair(to,make_pair(co,i)));
		edge[to].push_back(make_pair(from,make_pair(co,i)));
	}
	dijkstra(1);mem(vis,0);
	per(i,1,n){
		for(int j=0;j<vec[i].size();j++){
			tree[i].push_back(make_pair(vec[i][j].first,vec[i][j].second));
			tree[vec[i][j].first].push_back(make_pair(i,vec[i][j].second));
		}
	}
	queue<int> qu;
	qu.push(1);int cnt=0;vis[1]=true;
	while(!qu.empty()&&total<k&&total<n-1){
		int cur=qu.front();qu.pop();
		for(int i=0;i<tree[cur].size();i++){
			if(!vis[tree[cur][i].first]){
				ans[++total]=tree[cur][i].second;
				qu.push(tree[cur][i].first);
				if(total==k) break;
				vis[tree[cur][i].first]=true;
			}
		}
	}
	printf("%d\n",total);
	for(int i=1;i<=total;i++) printf("%d%c",ans[i],i==total?'\n':' ');
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值