• goj 他和她(最大生成树+最短路径)


    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代码:
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=105;
     4 const int INF=0x3f3f3f3f;
     5 int n,m,a,b,c,maxcost[maxn],dist[maxn],G[maxn][maxn],cost[maxn][maxn];bool vis[maxn],used[maxn];
     6 int prim(){//最大生成树
     7     for(int i=1;i<=n;++i)maxcost[i]=G[1][i];
     8     maxcost[1]=0;used[1]=true;
     9     int res=0;
    10     for(int i=1;i<n;++i){
    11         int k=-1;
    12         for(int j=1;j<=n;++j)
    13             if(!used[j]&&(k==-1||maxcost[k]<maxcost[j]))k=j;//每次找最大边权
    14         if(k==-1)break;
    15         used[k]=true;res+=maxcost[k];
    16         for(int j=1;j<=n;++j)
    17             if(!used[j])maxcost[j]=max(maxcost[j],G[k][j]);//更新周围点到已经归纳点的集合的最小权值
    18     }
    19     return res;
    20 }
    21 int dijkstra(){//最短路径
    22     for(int i=1;i<=n;++i)dist[i]=cost[1][i];
    23     dist[1]=0;vis[1]=true;
    24     for(int i=1;i<n;++i){
    25         int k=-1;
    26         for(int j=1;j<=n;++j)
    27             if(!vis[j]&&(k==-1||dist[k]>dist[j]))k=j;
    28         if(k==-1)break;
    29         vis[k]=true;
    30         for(int j=1;j<=n;++j)
    31             if(!vis[j])dist[j]=min(dist[j],dist[k]+cost[k][j]);
    32     }
    33     return dist[n];
    34 }
    35 int main(){
    36     while(~scanf("%d%d",&n,&m)){
    37         memset(vis,false,sizeof(vis));//全部初始化为未访问状态即false
    38         memset(used,false,sizeof(used));
    39         for(int i=1;i<=n;++i){
    40             for(int j=1;j<=n;++j){
    41                 G[i][j]=(i==j?0:-INF);//求最大生成树:初始化为最小值-INF
    42                 cost[i][j]=(i==j?0:INF);//求最短路径:初始化为最大值INF
    43             }
    44         }
    45         for(int i=1;i<=m;++i){
    46             scanf("%d%d%d",&a,&b,&c);
    47             G[a][b]=G[b][a]=max(G[a][b],c);//去重,代替最小权值
    48             cost[a][b]=cost[b][a]=min(cost[a][b],c);//去重,代替最大权值
    49         }
    50         int ok=prim();
    51         if(ok<=0)cout<<-1<<endl;//如果不大于0,说明不能从1到达n,直接输出-1
    52         else cout<<"spanning tree:"<<ok<<" shortest distance:"<<dijkstra()<<endl;
    53     }
    54     return 0;
    55 }
     
  • 相关阅读:
    小程序-文章:微信小程序常见的UI框架/组件库总结
    小程序-文章:微信第三方登录(静默授权和非静默授权)
    asterisk
    Java实现 洛谷 P1423 小玉在游泳
    Java实现 洛谷 P1423 小玉在游泳
    Java实现 洛谷 P1423 小玉在游泳
    Java实现 洛谷 P1035 级数求和
    Java实现 洛谷 P1035 级数求和
    Java实现 洛谷 P1035 级数求和
    Java实现 洛谷 P1035 级数求和
  • 原文地址:https://www.cnblogs.com/acgoto/p/9293832.html
Copyright © 2020-2023  润新知