Codeforces 1076D Edge Deletion 【最短路+贪心】

<题目链接>

题目大意:

n个点,m条边的无向图,现在需要删除一些边,使得剩下的边数不能超过K条。1点为起点,如果1到 i 点的最短距离与删除边之前的最短距离相同,则称 i 为 "good vertice",现在问你如果要使 "good vertice"最多,需要留下多少条边,并且输出这些边的序号。

解题分析:

我们最多只能留k条边 (或者是n-1条边,因为经过Dijkstra松弛后,其实只需要n-1条边就能使起点到所有点的最短距离仍然为未删边时的最短距离,想一下Dijkstra的松弛过程就能明白)。

那如何留下的 "good vertice" 最多呢?其实 "good vertice" 就是指我们尽量不要破坏原来的最短路径,那些越先通过Dijkstra松弛得到最短路的点的最短路径所需的维护的路径数量是最少的,所以我们贪心的将松弛的前K个点的之前的路劲记录即可,这样延伸出的连通块能够让其中所有的点到起点的最短距离等于原始的最短距离,同时他们所需维护的路径还是尽可能的少的。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <queue>
 4 #include <vector>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 #define M int(3e5+10)
 9 #define rep(i,s,t) for(int i=s;i<=t;i++)
10 #define pb push_back
11 #define clr(a,b) memset(a,b,sizeof(a))
12 #define INF ll(1e18)
13 typedef long long ll;
14 int cnt,head[M],loc[M];
15 bool vis[M];
16 vector<int>vec;
17 int n,m,k;
18 
19 template<typename T>    
20 inline T read(T&x){
21     x=0;int f=0;char ch=getchar();
22     while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar();
23     while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
24     return x=f?-x:x;
25 }
26 struct Edge{
27     int to,ord,next;
28     ll val;
29 }edge[M<<1];
30 
31 struct Node{
32     int ord;ll dist;
33     Node(int _ord=0,ll _dist=0):ord(_ord),dist(_dist){}
34     bool operator < (const Node &tmp)const {
35         return dist>tmp.dist;
36     }
37 }d[M];
38 void init(){
39     cnt=0;clr(head,-1);
40 }
41 void addedge(int u,int v,ll w,int c){
42     edge[++cnt].to=v;edge[cnt].val=w,edge[cnt].ord=c;
43     edge[cnt].next=head[u];head[u]=cnt;
44 }
45 void Dijkstra(){
46     priority_queue<Node>q;
47     for(int i=1;i<=n;i++)
48         d[i].dist=INF,d[i].ord=i,vis[i]=false;
49     d[1].dist=0;q.push(d[1]);
50     while(q.size()){
51         int u=q.top().ord;q.pop();
52         if(vis[u])continue;
53         vis[u]=true;vec.pb(loc[u]);
54         if(vec.size()==k+1)return ;       //因为起点的前一条边没有意义,所以这里是k+1结束
55         for(int i=head[u];~i;i=edge[i].next){
56             int v=edge[i].to;ll cost=edge[i].val;
57             if(!vis[v]&&d[v].dist>d[u].dist+cost){
58                 d[v].dist=d[u].dist+cost;
59                 loc[v]=edge[i].ord;       //记录这个点在 1--->v的最短路的最后一条边
60                 q.push(d[v]);
61             }
62         }
63     }
64 }   
65 int main(){
66     read(n);read(m);read(k);init();
67     rep(i,1,m){
68         int u,v;ll w;
69         read(u);read(v);read(w);
70         addedge(u,v,w,i);addedge(v,u,w,i);
71     }
72     k=min(k,n-1);     //k与(n-1)进行比较
73     Dijkstra();printf("%d\n",k);
74     rep(i,1,k)i==k?printf("%d\n",vec[i]):printf("%d ",vec[i]);    //因为起点的前一条边没有意义,所以这里从1开始输出
75 }

 

 

2019-02-12

转载于:https://www.cnblogs.com/00isok/p/10366087.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值