Problem Description:

大二上学期刚过完,平时成绩不错的小V参加了一个小型编程比赛,遇到一道题,虽然是书上的却不会做。于是找了在机房的他帮忙。
他:什么题目这么厉害,书上有却不会?
小V:就是给若干个城市编号,也告诉了我连接这些城市的公路的距离,也有一些城市间是没有直接的路的。求从一个城市到另外一个城市的最短距离。
他:这不很简单的单向最短路径么?照书敲都行啦。
小V:不是什么比赛都能带书。
他:那你自己敲出来还不行么?
小V:不会敲..完全下不了手,我只会考试那种画图的,写代码的话连思路都没有。
他:好吧- -!思路是这样的:
s为起点,w[u,v]为点u和v之间的边的长度(无边则长度设为一个很大的数,只要比w[]的最大值大就行),把s点到其他点的距离保存在一个数组里,假设是dis[]。
1.初始化:起点到起点的距离dis[s]设为0,s点到其他点(v)的距离设w[s,v],同时把所有的点都标记为未访问过,s点标记访问过。
2.循环n-1次:
①在没有访问过的点中取dis[]距离最小且未访问的点u,并标记为已访问。
②对于每个与u相邻的点v,执行Relax(u,v),也就是说,如果满足u点在最短路径上的距离+u到v点距离小于原本v点到最短路径上的距离就把v点到最短路径的距离更新成更短的距离。
3.结束。此时对于任意的u,dis[u]就是s到u的距离。
小V:标记?
他:开个数组表示就行了。
小V:那我试敲下。
他:等会,顺便先判断下这些城市能不能从任意一个城市i到另外一个城市j吧。
小V:生成树?
他:这么聪明?不过判断连通不一定要生成树,你还可以用搜索、并查集,搜索就看能不能一次就搜遍,集合就看是不是它们在同一连通分量,不是就把它们合并在一个集合里,最终判断是不是全部点同属一个集合就行。
小V:那个叫什么并查集的怎么听起来跟克鲁斯卡尔算法那么像。
他:kruskal是可以用并查集优化的。不过既然你这么说了,那就干脆也求个最小生成树的值吧,即用公路长度和最小的n-1个公路将n个城市连在一起,求这n-1条路的公路长度。
小V:那代码上跟最短路那个算法有什么区别?
他:改下Relax()的条件,每加入一个点u,看其他跟该点有边的点v,v到树上的距离是不是小于u到树上源点的距离,是就更新,再把生成树上那些点的权值加起来就是答案。
大概半小时后,小V敲得差不多了。
他:看你都敲这么多了,也告诉你这么多了,不如加个难度,改求最大生成树,这样,我给你4个例子,你对照下答案。
经过比对,答案还是不对。这时他喵了一眼就看出是初始化问题,但他没有告诉她。因为他知道这是她必须跨过的坎,有多少学生能把各种算法的原理讲得很流畅,却写不出代码。
而对于她,他希望她能解决的不只是这个问题,因为这样才能实现他的心愿:一!起!刷!题! Hints:不要轻易放弃,水题虽多,AC不易。

Input:

多组数据,每组数据第一行是两个数N,M(1<=N<=100,0<=M<=1000),N表示城市个数,城市从1开始编号,M表示公路数目,编号为1的城市为起点,编号为N的为终点,接下来有M行,每行两个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示有一条长度为C的公路连接AB两城市。数据保证1号城市不是孤立的。

Output:

如果从1号城市出发,不能到其他所有城市,则输出-1,否则按样例格式输出最大生成树的值和从1号城市到N号城市的最短距离。

Sample Input:

3 3
1 2 45
1 3 20
3 1 10
3 1
1 2 5
2 2
2 1 250
1 2 520
4 7
1 4 88
2 4 1
4 2 50
3 1 6
4 1 1000
4 3 30
2 3 100

Sample Output:

spanning tree:65 shortest distance:10
-1
spanning tree:520 shortest distance:250
spanning tree:1150 shortest distance:36
解题思路:最大生成树即将prim算法中每次找最小权值改为找最大权值,每加入一个点更新一下用最大权值代替原来的最小值即可。这题还要考虑重边的情况,简单处理,简单水过。
AC代码:
 #include<bits/stdc++.h>
using namespace std;
const int maxn=;
const int INF=0x3f3f3f3f;
int n,m,a,b,c,maxcost[maxn],dist[maxn],G[maxn][maxn],cost[maxn][maxn];bool vis[maxn],used[maxn];
int prim(){//最大生成树
for(int i=;i<=n;++i)maxcost[i]=G[][i];
maxcost[]=;used[]=true;
int res=;
for(int i=;i<n;++i){
int k=-;
for(int j=;j<=n;++j)
if(!used[j]&&(k==-||maxcost[k]<maxcost[j]))k=j;//每次找最大边权
if(k==-)break;
used[k]=true;res+=maxcost[k];
for(int j=;j<=n;++j)
if(!used[j])maxcost[j]=max(maxcost[j],G[k][j]);//更新周围点到已经归纳点的集合的最小权值
}
return res;
}
int dijkstra(){//最短路径
for(int i=;i<=n;++i)dist[i]=cost[][i];
dist[]=;vis[]=true;
for(int i=;i<n;++i){
int k=-;
for(int j=;j<=n;++j)
if(!vis[j]&&(k==-||dist[k]>dist[j]))k=j;
if(k==-)break;
vis[k]=true;
for(int j=;j<=n;++j)
if(!vis[j])dist[j]=min(dist[j],dist[k]+cost[k][j]);
}
return dist[n];
}
int main(){
while(~scanf("%d%d",&n,&m)){
memset(vis,false,sizeof(vis));//全部初始化为未访问状态即false
memset(used,false,sizeof(used));
for(int i=;i<=n;++i){
for(int j=;j<=n;++j){
G[i][j]=(i==j?:-INF);//求最大生成树:初始化为最小值-INF
cost[i][j]=(i==j?:INF);//求最短路径:初始化为最大值INF
}
}
for(int i=;i<=m;++i){
scanf("%d%d%d",&a,&b,&c);
G[a][b]=G[b][a]=max(G[a][b],c);//去重,代替最小权值
cost[a][b]=cost[b][a]=min(cost[a][b],c);//去重,代替最大权值
}
int ok=prim();
if(ok<=)cout<<-<<endl;//如果不大于0,说明不能从1到达n,直接输出-1
else cout<<"spanning tree:"<<ok<<" shortest distance:"<<dijkstra()<<endl;
}
return ;
}
 

ACM_他和她(最大生成树+最短路径)的更多相关文章

  1. ACM主要算法

    ACM主要算法ACM主要算法介绍 初期篇 一.基本算法(1)枚举(poj1753, poj2965)(2)贪心(poj1328, poj2109, poj2586)(3)递归和分治法(4)递推(5)构 ...

  2. ACM常用算法

    数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 一维线段树 二维 ...

  3. ACM需要掌握算法

    数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 一维线段树 二维 ...

  4. ACM用到的算法。先做个笔记,记一下

    ACM 所有算法 数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 ...

  5. ACM算法目录

    数据结构 栈,队列,链表 •哈希表,哈希数组 •堆,优先队列 双端队列 可并堆 左偏堆 •二叉查找树 Treap 伸展树 •并查集 集合计数问题 二分图的识别 •平衡二叉树 •二叉排序树 •线段树 一 ...

  6. ACM技能表

    看看就好了(滑稽) 数据结构 栈 栈 单调栈 队列 一般队列 优先队列/单调队列 循环队列 双端队列 链表 一般链表 循环链表 双向链表 块状链表 十字链表 邻接表/邻接矩阵 邻接表 邻接多重表 Ha ...

  7. 图论相关知识(DFS、BFS、拓扑排序、最小代价生成树、最短路径)

    图的存储 假设是n点m边的图: 邻接矩阵:很简单,但是遍历图的时间复杂度和空间复杂度都为n^2,不适合数据量大的情况 邻接表:略微复杂一丢丢,空间复杂度n+m,遍历图的时间复杂度为m,适用情况更广 前 ...

  8. 信息奥赛一本通1486: CH 6202 黑暗城堡 最短路径生成树计数

    1486:黑暗城堡 [题目描述] 知道黑暗城堡有 N 个房间,M 条可以制造的双向通道,以及每条通道的长度. 城堡是树形的并且满足下面的条件: 设 Di为如果所有的通道都被修建,第 i 号房间与第 1 ...

  9. acwing349 黑暗城堡 (最短路径生成树)

    求出最短树,用乘法原理统计答案就行了(模拟prim过程). 不知道说什么了,直接上代码: 1 #include<cstring> 2 #include<iostream> 3 ...

随机推荐

  1. OpenCV+Python识别车牌和字符分割的实现

    本篇文章主要基于python语言和OpenCV库(cv2)进行车牌区域识别和字符分割,开篇之前针对在python中安装opencv的环境这里不做介绍,可以自行安装配置! 车牌号检测需要大致分为四个部分 ...

  2. 移动端禁止滑动的js处理方式

    下面是禁止移动端滑动事件的方式,慎用  document.querySelector('body').addEventListener('touchmove', function (ev) {     ...

  3. JUnit基本用法

    JUnit的一些注意事项: 测试方法必须使用@Test修饰 测试方法必须使用public void进行修饰,不能带参数 一般使用单元测试会新建一个test目录存放测试代码,在生产部署的时候只需要将te ...

  4. linux下使用tomcat下载中文文件报404not find

    首先,大神指路:http://bbs.csdn.net/topics/391065011?page=1 相关的一些命令: 查看当前系统字符编码:env locale 查看系统支持的字符编码:local ...

  5. Jboss 服务器SSL证书安装指南

    1.获取服务器证书 将证书签发邮件中的从BEGIN到 END结束的服务器证书内容(包括“-----BEGIN CERTIFICATE-----”和“-----END CERTIFICATE-----” ...

  6. java方法的虚分派和方法表

    java:方法的虚分派(virtual dispatch)和方法表(method table) Java方法调用的虚分派 虚分配(Virtual Dispatch) 首先从字节码中对方法的调用说起.J ...

  7. 九度oj 题目1473:二进制数

    题目描述: 大家都知道,数据在计算机里中存储是以二进制的形式存储的. 有一天,小明学了C语言之后,他想知道一个类型为unsigned int 类型的数字,存储在计算机中的二进制串是什么样子的. 你能帮 ...

  8. 中庸之道(codevs 2021)

    题目描述 Description 给定一个长度为N的序列,有Q次询问,每次询问区间[L,R]的中位数. 数据保证序列中任意两个数不相同,且询问的所有区间长度为奇数. 输入描述 Input Descri ...

  9. Ubuntu 16.04添加启动图标到Dash Home中

    一.添加图标: 图标信息在以下两处地方: /usr/share/applications ~/.local/share/applications(用户独立配置存放地方,是个隐藏文件夹) 图标信息文件以 ...

  10. Eclipse修改默认包路径的起始文件夹

    一般新建的Java Project项目都是从src文件夹开始的,那么通过下面的操作可以自定义修改起始文件夹. 1.项目右键->[Properties] 如果不能修改时,可以直接删除后再添加回来.