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

 

题意:

给你n个点m条边的无向图,其中1号节点是市中心,你现在最多只能保留k条边,并要求所有点到市中心的最短路尽量不变(也就是说设点i到点1的最短路为di,那么删边之后,要保证尽可能多的点,它到1的最短路仍然是di),求保留哪k条边,当然你可以保留<k条边就是了

 

思路:

对于每个点u,一定存在last[u]表示从1到u的走最短路,上一个点是哪个点,当然可能不唯一,不过无所谓

这样求一遍1到所有点的最短路之后,对于每个点u,last[u]向u连一条边,这样可以得到一棵最短路树

然后保留最短路树上的边就行了

就这么简单,不过求最短路的时候尽量不要用SPFA,因为它可能被卡到O(nm)

 

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
typedef struct Road
{
	LL len;
	int x, y, id;
	bool operator < (const Road &b) const
	{
		if(len>b.len)
			return 1;
		return 0;
	}
}Road;
vector<Road> G[300005], F[300005];
LL dp[300005], ans[300005];
int last[300005], vis[300005], k;
priority_queue<Road> q;
void Sech(int u)
{
	int i, v;
	for(i=0;i<F[u].size();i++)
	{
		v = F[u][i].y;
		if(k>=1)
		{
			printf("%d ", F[u][i].id);
			k--;
		}
		Sech(v);
	}
}
int main(void)
{
	Road now, temp;
	int x, y, n, m, i, v;
	scanf("%d%d%d", &n, &m, &k);
	memset(dp, -1, sizeof(dp));
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%lld", &x, &y, &now.len), now.id = i;
		now.x = x, now.y = y, G[x].push_back(now);
		now.x = y, now.y = x, G[y].push_back(now);
	}
	dp[1] = last[1] = 0;
	for(i=0;i<G[1].size();i++)
	{
		q.push(G[1][i]);
		vis[G[1][i].id] = 1;
	}
	while(q.empty()==0)
	{
		now = q.top();
		q.pop();
		if(dp[now.y]==-1)
		{
			dp[now.y] = now.len;
			last[now.y] = now.x;
			F[now.x].push_back(now);
			for(i=0;i<G[now.y].size();i++)
			{
				v = G[now.y][i].y;
				temp.x = now.y, temp.y = v, temp.id = G[now.y][i].id;
				if(vis[temp.id]==0)
				{
					temp.len = G[now.y][i].len+dp[now.y];
					q.push(temp);
					vis[temp.id] = 1;
				}
			}
		}
	}
	if(k>=n-1)
		k = n-1;
	printf("%d\n", k);
	Sech(1);
	printf("\n");
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值