Educational Codeforces Round 54 (Rated for Div. 2) D. Edge Deletion(Dijkstra理解题)

思路来源

马石页老师&&张舟亢学长

题意

给你一个n点m边的原图,要求只保留这个图的k条边,

使子图上的最短路点尽可能多。

最短路点是指到1号节点的最短距离,在原图和子图的值相同。

要求输出子图边的编号,按加入的顺序对边进行编号1-m。

题解

模拟dijkstra的入堆过程,

由于dijkstra的贪心选点思想,每次一定选的是到顶点最近的点。

因此,必有一次松弛操作,使得一条边贡献出一个最短路点。

因此,开一个存结构体的优先队列,

我们只要一松弛,就把贡献松弛的边的id塞进优先队列里,

取出优先队列顶的点的时候(已按距离从小到大排序)

查一下是从哪个id的边使这个点成为到顶点的最短距离点(即当前被贪心选中的点),

然后把这个id加到ans里,满足k条return即可。

心得

最短路题变种好多啊QAQ

稍微考点概念就不会了GG

这题没开ll会被hack掉,

CF榜上hack率惊人QAQ

代码

#include <iostream>
#include <algorithm> 
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const int INF=0x3f3f3f3f;
const int maxn=3e5+10; 
const int mod=1e9+7;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int> 
#define si set<int>
#define pli pair<ll,int> 
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a)) 
using namespace std;
int head[maxn],cnt,n,m,k;
bool vis[maxn];
ll dis[maxn]; 
struct edge{int to,nex,id;ll w;}e[maxn<<1];
struct node
{
  ll w;
  int id,v;
  node(ll a,int b,int c):w(a),id(b),v(c){
  } 
};
bool operator>(node a,node b)
{
	return a.w>b.w;
}
priority_queue<node,vector<node>,greater<node> >q;
vector<int>ans;
void init()
{
	rep(i,0,n-1)dis[i]=1e18;
	cnt=0;
	mem(head,-1);
}
void add(int u,int v,ll w)
{
	e[cnt].to=v;
	e[cnt].w=w;
	e[cnt].id=cnt/2;
	e[cnt].nex=head[u];
	head[u]=cnt++;
}
void dijkstra(int s)
{
	q.push(node(0,-1,s));//说明从哪条边转移到这点的 
	dis[s]=0;
	while(!q.empty())
	{
		node tmp=q.top();
		q.pop();
		ll w=tmp.w;
		int id=tmp.id,v=tmp.v;
		if(vis[v]||w>dis[v])continue;
		vis[v]=1;
		if(id!=-1)ans.push_back(id);
		if(ans.size()==k)return;
		for(int i=head[v];~i;i=e[i].nex)
		{
			int to=e[i].to,id=e[i].id;
			ll w=e[i].w;
			if(dis[to]>dis[v]+w)
			{
				dis[to]=dis[v]+w;
				q.push(node(dis[to],id,to));
			}
		}
	}
} 
int main()
{ 
    sci(n),sci(m),sci(k);
    init();
    rep(i,0,m-1)
    {
    	int u,v;
    	ll w;
    	sci(u),sci(v),scll(w);
    	u--,v--;
    	add(u,v,w);
    	add(v,u,w);
    }
    dijkstra(0);
    int len=ans.size();
    printf("%d\n",len);
    if(len)
    {
    	printf("%d",1+ans[0]);
    	rep(i,1,len-1)
    	printf(" %d",1+ans[i]);
    	puts("");
    }
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值