CF 545E Paths and Trees

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

思路 :单源最短路径 + 贪心 .用Dijkstra 或spfa 算法 求每个点到源点的最短路径,并在记录当前用来更新每个点最短距离的那条边(即pre[i]记录点i所对应的变)。

    若当前这条边能使得某个点到源点的距离变小则更新该点到源点的距离,并记录更新该点的边; 若当前这条边更新某节点后,使得该点到源点的距离不变(即:d[e[t].to] = d[e[t].from] + e[t].length ) 则比较这条边与当前该点所记录的边的长度大小,若这条边比改点所记录的边长度要小(即e[pre[e[t].to]].length > e[t].length),则更新改点所记录的边(pre[e[t].to] = t)。

代码 :

  1. #include<stdio.h>
  2. #include<iostream>
  3. #include<string.h>
  4. #include<stdlib.h>
  5. #include<queue>
  6. #define INF 0x7fffffffffffffff
  7. #define pii pair<long long,long long>
  8. using namespace std;
  9. long long s,n,m,pre[300002],tag[600002],u[600002],v[600002],next[600002],first[300002];
  10. long long sum,d[300002],w[600002];
  11. priority_queue<pii,vector<pii>,greater<pii> > Q;
  12. bool vis[300002];
  13. void input(){
  14.   long long i,j,a,b,c;
  15.   for(i=1;i<=n;i++)
  16. first[i] = -1;
  17. for(i=1;i<=m;i++){
  18. scanf("%I64d %I64d %I64d",&u[i],&v[i],&w[i]);
  19. u[i+m] = v[i] ;
  20. v[i+m] = u[i] ;
  21. w[i+m] = w[i] ;
  22. next[i] = first[u[i]];
  23. first[u[i]] = i ;
  24. next[i+m] = first[v[i]];
  25. first[v[i]] = i+m ;
  26. }
  27.   scanf("%I64d",&s);
  28. }
  29. void Dijkstra(){
  30. long long i,j;
  31. memset(vis,0,sizeof(vis));
  32. memset(tag,0,sizeof(tag));
  33. for(i=1;i<=n;i++)
  34. pre[i] = -1 ;
  35. for(i=1;i<=n;i++)
  36. d[i] = INF;
  37. d[s] = 0;
  38. Q.push(make_pair(d[s],s));
  39. while(!Q.empty()){
  40. pii t = Q.top();
  41. Q.pop();
  42. long long x = t.second;
  43. if(vis[x])
  44. continue;
  45. vis[x] = true;
  46. for(long long e=first[x]; e!=-1; e=next[e]){
  47. if(d[v[e]] > d[x] + w[e] && d[x] < INF){
  48. pre[v[e]] = e;
  49. d[v[e]] = d[x] + w[e] ;
  50. Q.push(make_pair(d[v[e]],v[e]));
  51. }
  52. else if(d[v[e]] == d[x] + w[e] && d[x] < INF && w[pre[v[e]]] > w[e]){
  53. pre[v[e]] = e;
  54. Q.push(make_pair(d[v[e]],v[e]));
  55. }
  56. }
  57. }
  58. int main(){
  59. long long i,j;
  60. while(scanf("%I64d%I64d",&n,&m) == 2){
  61. input();
  62. sum = 0;
  63. Dijkstra();
  64. for(i=1;i<=n;i++){
  65. sum += w[pre[i]] ;
  66. tag[pre[i]] = 1 ;
  67. }
  68. printf("%I64d\n",sum);
  69. long long count = 0;
  70. for(i=1;i<=2*m;i++)
  71. if(tag[i]){
  72. if(i > m){
  73. if(count != 0)
  74. printf(" %I64d",i-m);
  75. else
  76. printf("%I64d",i-m);
  77. }
  78. else if(i<=m){
  79. if(count != 0)
  80. printf(" %I64d",i);
  81. else
  82. printf("%I64d",i);
  83. }
  84. count ++ ;
  85. }
  86. printf("\n");
  87. }
  88. return 0;
  89. }
时间: 2024-11-14 07:11:20

CF 545E Paths and Trees的相关文章

545E. Paths and Trees

题目链接 题意:给定一个无向图和一个点u,找出若干条边组成一个子图,要求这个子图中u到其他个点的最短距离与在原图中的相等,并且要求子图所有边的权重之和最小,求出最小值并输出子图的边号. 思路:先求一遍最短路,从所有到i点的满足最短路的边中选一条权最小的边. Java程序 import java.io.PrintStream; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import

Codeforces Round #303 (Div. 2) E. Paths and Trees (最短路+变形最小生成树)

题目地址:E. Paths and Trees 模拟了一场CF,这场实在太水了..边玩边做的..最后半分钟交了一发E题..不幸AK绝杀失败.... 首先的思路肯定是先求最短路,把可能为最短路的边挑出来,然后第二步我本来写的是直接用无向图的最小生成树,于是绝杀失败...后来才发现这样是不行的..因为边是有向边,而且每个点的入度要保证只有一个才行.于是我就把最小生成树的边弄成有向边,然后判定一下每个点的入度保证为1.然后就过了.. 代码如下: #include <iostream> #includ

「日常训练」Paths and Trees(Codeforces Round 301 Div.2 E)

题意与分析 代码 #include <bits/stdc++.h> #define MP make_pair #define PB emplace_back #define fi first #define se second #define ZERO(x) memset((x), 0, sizeof(x)) #define ALL(x) (x).begin(),(x).end() #define rep(i, a, b) for (repType i = (a); i <= (b);

Codeforce 水题报告(2)

又水了一发Codeforce ,这次继续发发题解顺便给自己PKUSC攒攒人品吧 CodeForces 438C:The Child and Polygon: 描述:给出一个多边形,求三角剖分的方案数(n<=200). 首先很明显可能是区间dp,我们可以记f[i][j]为从i到j的这个多边形的三角剖分数,那么f[i][j]=f[i][k]*f[j][k]*(i,j,k是否为1个合格的三角形) CodeForces 438D:The Child and Sequence 描述:给一个序列,要求支持区

topic model - LDA 1

http://blog.csdn.net/pipisorry/article/details/42129099 step1 :install gensim step 2 :Corpora and Vector Spaces 将用字符串表示的文档转换为用id表示的文档向量: documents = ["Human machine interface for lab abc computer applications", "A survey of user opinion of

文本相似性计算

文本相似性计算三个阶段: 1. 字面的匹配相似 2. 词汇的匹配相似 3. 语义的匹配相似 一.JaccardSimilarity方法 对文本进行分词,然后对每一个单词分配一个唯一的ID(token),为了计算文本之间的相似性.JaccardSimilarity方法的计算方法是: 两个集合的交集/两个集合的并集二.文本的向量化 文本->向量化为向量->向量空间中的某一个点->求两个点(即两个文本)之间的距离->得到文档的相似性 2.1 简单的向量化 为每一个词语分配一个唯一的ID,

树的直径| CF#615Div3 F. Three Paths on a Tree

F. Three Paths on a Tree 思路 两种方法: 1.两次bfs求树的直径,顺便求出一个直径端点到所有点的最短距离:再bfs一次,求另一个直径上的端点到其它所有点的最短距离:之后枚举第三个端点(不等于端点1和端点2),dis(a,b) + dis(b,c) + dis(a,c) 再除以 2 就是最终答案,因为每个路径走了两次所以除以2. 2.dfs求树的直径,记录直径上的所有点.从直径上的所有点去搜索它们到不在直径上的点的最远距离.最后直径+这个最远距离就是答案 代码1 bfs

cf 558A Lala Land and Apple Trees

#include<stdio.h> #include<algorithm> #include<string.h> using namespace std; struct data { int x; int a; }; data l[1024],r[1024]; bool c1(data q,data p) { return q.x<p.x; } bool c2(data q,data p) { return q.x>p.x; } int main() { i

CF Gym102028G Shortest Paths on Random Forests

传送门 这题要求的期望,就是总权值(所有不在同一个连通块点对的贡献+同一连通块点对的贡献)/总方案(森林个数) 先求森林个数,森林是由一堆树组成的,而根据purfer序列,一棵\(n\)个点的有标号的树的个数为\(n^{n-2}\),然后因为点有标号所以可以考虑EGF,设树的EGF为\(F(x)\),那么森林的生成函数为\(e^{F(x)}\) 然后是不在同一个连通块点对的贡献,这等于不在同一个连通块点对个数\(*m^2\),然后不在同一个连通块点对个数又等于总点对个数\(-\)在同一个连通块点