[题目大意]
 题目将从某点出发的所有最短路方案中,选择边权和最小的最短路方案,称为最短生成树。

 题目要求一颗最短生成树,输出总边权和与选取边的编号。
[题意分析]
 比如下面的数据:
 5 5
 1 2 2
 2 3 2
 3 4 16
 1 5 18
 4 5 2
 1

 这个图对于从 1 出发,有两种最短路。

 

这种最短路方案中 dis[2]=2,dis[3]=4,dis[4]=20,dis[5]=18。边权总和 Sum=44

但如果这样选边,1点到各点的距离依然为最短路,但Sum降为了24

那么如何选择到最优的方案呢。 由于最短路方案构成的图一定是一棵树,所以我们可以将 除源点外 的所有顶点搞一个贪心。

改写dijkstra算法(c[]数组用来存取与该点连接的边的cost,s[]数组用来存取与该点连接的边的编号):

const ll inf=0x7fffffffffffff;
struct Edge{
int to,cost,id;
Edge(int T,int C,int D):to(T),cost(C),id(D){}
};
typedef pair<long long,int> P;
vector<Edge>G[];
ll d[],c[];
void dij(int u){
fill(d,d+n+,inf);
fill(c,c+n+,inf);
d[u]=;
priority_queue<P,vector<P>,greater<P>> q;
q.push(P(d[u],u));
while(!q.empty()){
P p=q.top();
q.pop();
int v=p.second;
if(d[v]<p.first) continue;
for(int i=;i<G[v].size();i++){
Edge e=G[v][i];
if(d[e.to]>d[v]+e.cost){
d[e.to]=d[v]+e.cost;
s[e.to]=e.id;
c[e.to]=e.cost;
q.push(P(d[e.to],e.to));
}
else if(d[e.to]==d[v]+e.cost&&c[e.to]>e.cost){
s[e.to]=e.id;
c[e.to]=e.cost;
}
}
}
}

当有多条路通往一个顶点,且这两种路线cost相同时,我们可以将 通往该顶点的边该顶点 绑定起来,我们希望每个顶点都能绑定合法的(不影响最短路的)且权值最小的边。

在dijkstra算法中我们每次挑选优先队列中权值最小的路。当碰上两条路cost相等的时候,我们选择与下一个点连接且边权最小的那一条边与下一个点绑定(Cost[nextV]=e.cost)。

* 由于最短路中从源点通往每个点的路可以组成一颗树 且 点只与从源点走向该点的边相绑定,所以一个点 一定可以 绑定一条边。

选取完毕后,我们只需要遍历 c[] 数组求出总花费,再遍历 s[] 数组输出每个点绑定的边的编号即可。

***Code:

 #include<bits/stdc++.h>
#define ll long long
using namespace std;
int m,n,s[];
const ll inf=0x7fffffffffffff;
struct Edge{
int to,cost,id;
Edge(int T,int C,int D):to(T),cost(C),id(D){}
};
typedef pair<long long,int> P;
vector<Edge>G[];
ll d[],c[];
void dij(int u){
fill(d,d+n+,inf);
fill(c,c+n+,inf);
d[u]=;
priority_queue<P,vector<P>,greater<P>> q;
q.push(P(d[u],u));
while(!q.empty()){
P p=q.top();
q.pop();
int v=p.second;
if(d[v]<p.first) continue;
for(int i=;i<G[v].size();i++){
Edge e=G[v][i];
if(d[e.to]>d[v]+e.cost){
d[e.to]=d[v]+e.cost;
s[e.to]=e.id;
c[e.to]=e.cost;
q.push(P(d[e.to],e.to));
}
else if(d[e.to]==d[v]+e.cost&&c[e.to]>e.cost){
s[e.to]=e.id;
c[e.to]=e.cost;
}
}
}
}
int main(){
int u,v,co;
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
scanf("%d%d%d",&u,&v,&co);
G[u].push_back(Edge(v,co,i));
G[v].push_back(Edge(u,co,i));
}
scanf("%d",&u);
dij(u);
ll sum=;
for(int i=;i<=n;i++){
if(i!=u) sum+=c[i];
}
cout<<sum<<endl;
for(int i=;i<=n;i++){
if(i!=u) cout<<s[i]<<' ';
}
return ;
}

2017/7/13

Codeforces 545E. Paths and Trees[最短路+贪心]的更多相关文章

  1. Codeforces 545E. Paths and Trees 最短路

    E. Paths and Trees time limit per test: 3 seconds memory limit per test: 256 megabytes input: standa ...

  2. Codeforces Round #303 (Div. 2) E. Paths and Trees 最短路+贪心

    题目链接: 题目 E. Paths and Trees time limit per test 3 seconds memory limit per test 256 megabytes inputs ...

  3. [Codeforces 545E] Paths and Trees

    [题目链接] https://codeforces.com/contest/545/problem/E [算法] 首先求 u 到所有结点的最短路 记录每个节点最短路径上的最后一条边         答 ...

  4. Codeforces Round #303 (Div. 2)E. Paths and Trees 最短路

    E. Paths and Trees time limit per test 3 seconds memory limit per test 256 megabytes input standard ...

  5. 545E. Paths and Trees

    题目链接 题意:给定一个无向图和一个点u,找出若干条边组成一个子图,要求这个子图中u到其他个点的最短距离与在原图中的相等,并且要求子图所有边的权重之和最小,求出最小值并输出子图的边号. 思路:先求一遍 ...

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

    <题目链接> 题目大意: n个点,m条边的无向图,现在需要删除一些边,使得剩下的边数不能超过K条.1点为起点,如果1到 i 点的最短距离与删除边之前的最短距离相同,则称 i 为 " ...

  7. CF 545E Paths and Trees

    题目大意:给出n个点,m条无向边,每条边有长度.求一棵树,要求树上的每个点到源点距离最小的前提下,使得树上的边的长度和最小.输出树上边的总长度,以及树上的边的序号(按输入顺序 1...m). 思路 : ...

  8. codeforces 545E E. Paths and Trees(单源最短路+总权重最小)

    E. Paths and Trees time limit per test:3 seconds memory limit per test:256 megabytes input:standard ...

  9. Codeforces Round #303 (Div. 2) E. Paths and Trees Dijkstra堆优化+贪心(!!!)

    E. Paths and Trees time limit per test 3 seconds memory limit per test 256 megabytes input standard ...

随机推荐

  1. Ubuntu 16.04 not a com32r image

    安装Ubuntu16.04,出现题目中的错误,解决方法如下 重点:开机后按TAB键,在随后出现的命令行提示符中输入live 既可,之后的过程就是正常的过程了!

  2. android 常用第三方github工程

    这里有个汇总的网址:http://androidxy.com/zh/page/latest/-1/0 数据库:greenDao 参考:GreenDao3.2的使用 控件注解:Butterknife 图 ...

  3. calendar.getTimeInMillis() 和 System.currentTimeMillis() 的区别

    @Test public void test01(){ Calendar calendar=Calendar.getInstance(); // calendar.set(2019,06,04,16, ...

  4. 小白学phoneGap《构建跨平台APP:phoneGap移动应用实战》连载二(生命周期)

    4.1 什么是生命周期 想要真正地理解PhoneGap应用开发的内涵,首先需要理解什么是生命周期.这在字面上其实非常容易理解,一个应用从开始运行被手机加载到应用被退出之间的过程就称之为一个生命周期.为 ...

  5. uvm_subscriber——告诉她我们来过

    Subscribers are basically listeners of an analysis port. They subscribe to a broadcaster and receive ...

  6. Linux基础知识介绍

    1.Linux知识说明1)文件位置 1)/etc/inittab2)模式介绍 0:挂起模式-不推荐 1:单用户模式-只有管理员可以进入该模式,可以修改root密码,处理有登录权限而没有修改文件的权限问 ...

  7. OpenGL列主元矩阵和列主序存储

    OpenGL矩阵要考虑两个点,一个是向量如何排布,一个是矩阵如何存储和恢复. 1.排布 排布决定了运算的顺序.OpenGL使用的是列主元,它的意思就是一个4X4的矩阵是由4个列向量构成(这里的v1,v ...

  8. Codeforces Gym 100650B Countdown (离线)

    题目链接:http://codeforces.com/gym/100650 根据给出的树和d,求出一些结点,这些结点形成子树的第d层结点数应该尽量多,具体要求可以参考题目. dfs一个结点前保存询问深 ...

  9. 将回车键转换为Tab键

    实现效果: 知识运用: KeyEventArgs类的KeyValue属性 public int KeyValue {get;} //获取KeyDown或KeyUp事件的键盘值 SendKeys类的Se ...

  10. c++ 中的函数调用中的参数传递

    概述 初学 \(c++\),一直搞不懂其参数传递方式.故找到一篇不错的文章:刘志华的深入探讨C++语言中参数传递问题.亲自实践一遍,并作此记录,以加深印象.     主要内容 本文主要分为五个小部分, ...