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

 题目要求一颗最短生成树,输出总边权和与选取边的编号。
[题意分析]
 比如下面的数据:
 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

最新文章

  1. 使用VisualVM检测
  2. RabbitMQ框架学写笔记-20161201
  3. mongogogog
  4. 关于移动App的五个提问
  5. 启动Memcache,出现memcached: error while loading shared libraries: libevent-1.4.so.1: cannot open shared
  6. shell常见语法
  7. Spark1.0 安装
  8. Spring Tool Suite(简称STS)针对SimpleDateFormat.pase函数的实参值不做检验,异常直接默认值之
  9. 使用RESTClient插件数据模拟(GET,POST)提交
  10. 查看SQL SERVER 加密存储过程,函数,触发器,视图
  11. YII 1.0 隐藏单入口index.php 设置路由与伪静态
  12. django MVC模式 数据库的操作mysql
  13. NancyFX 附录: Nuget程序包
  14. boston_housing-多分类问题
  15. struts2自定义转换器
  16. Memcached详解
  17. 步步为营-90-SEO(url重写+超链接技巧)
  18. Ubuntu 18.04 安装Virtual Box or VMWare workstation Pro 14
  19. 【Java线程安全】 — 常用数据结构及原理(未完结)
  20. python之路——12

热门文章

  1. 打造自己的JavaScript武器库
  2. Json字符串转excel表格文件
  3. uvm_reg_field——寄存器模型(二)
  4. js数组去重方法包括Es6(方法有很多,但是需要考虑兼容性和数据类型场景)
  5. Jquery 错误提示插件
  6. 使用ABAP编程实现对微软Office Word文档的操作
  7. make与makefile的几个例子和(自己写一下,汗!忘记了!)总结
  8. 关于img
  9. caffe layer层cpp、cu调试经验和相互关系
  10. js获取当前日期、前一天、后一天的日期的例子