2021-2022-1 ACM集训队每周程序设计竞赛 - 问题 D: 跑图 - 题解

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-2022-1 ACM集训队每周程序设计竞赛 - 问题 D: 跑图 - 题解相关的知识,希望对你有一定的参考价值。


跑图

时间限制:2秒
空间限制:256M


题目描述

小T给你了一个 N N N M M M边的无向带权连通简单图(无向、带权、连通、无自环、无重边)

其中第 i ( 1 ≤ i ≤ M ) i(1\\leq i\\leq M) i(1iM)条边连接点 a i a_i ai b i b_i bi,权重是 c i c_i ci

输出不属于任意两点的最短路径的边的条数。


输入描述

  • 2 ≤ N ≤ 100 2\\leq N\\leq 100 2N100
  • N − 1 ≤ M ≤ m i n ( N ( N − 1 ) 2 , 1000 ) N-1\\leq M\\leq min(\\frac{N(N-1)}{2},1000) N1Mmin(2N(N1),1000)
  • 1 ≤ a i , b i ≤ N 1\\leq a_i,b_i\\leq N 1ai,biN
  • 1 ≤ c i ≤ 1000 1\\leq c_i\\leq 1000 1ci1000
  • c i c_i ci 是整数
  • 给定的图没有自环也没有重边
  • 给定的图是连通图

输入的格式是:

N M
a1 b1 c1
a2 b2 c2
...
am bm cm

输出描述

输出不属于任意两点的最短路径的边的条数。
即:如果点 a a a和点 b b b的最短路径经过了边 c c c,那么 c c c不是答案中的一条。


样例一

输入

3 3
1 2 1
1 3 1
2 3 3

输出

1

提示

  • 从点 1 1 1到点 2 2 2,最短路径是 1 → 2 1\\rightarrow2 12,权重为 1 1 1
  • 从点 2 2 2到点 3 3 3,最短路径是 2 → 3 2\\rightarrow3 23,权重为 1 1 1
  • 从点 3 3 3到点 1 1 1,最短路径是 3 → 2 → 1 3\\rightarrow2\\rightarrow1 321,权重为 2 2 2

所以第 3 3 3条边(连接点 1 1 1和点 3 3 3,权重是 3 3 3)不属于上面任何两点之间的最短路径,因此答案是 1 1 1(条)。


题目分析

这题其实是弗洛伊德算法,我们可以算出来任意两点之间的最短路径,遍历给定的每一条边,如果这条边连接的两点的最短距离小于这条边的权重,那么这条边一定不是某个最短路径的一部分(有权重更短的边),累加到结果中即可。

简单描述一下弗洛伊德算法:

定义 P ( i , j , k ) P(i,j,k) P(i,j,k)为:从 v i v_i vi v j v_j vj,由序号不大于 k k k的顶点为中间点(或直达)可构成的最短路径。
那么递推公式为 P ( i , j , k ) = m i n ( P ( i , k , k − 1 ) + P ( k , j , k − 1 ) , P ( i , j , k − 1 ) ) P(i,j,k) = min(P(i,k,k-1) + P(k,j,k-1), P(i,j,k-1)) P(i,j,k)=min(P(i,k,k1)+P(k,j,k1),P(i,j,k1))

其实我们可以省去一维的空间,用 a [ i ] [ j ] a[i][j] a[i][j]代表从 i i i j j j的最短路径。那么如何体现“序号不大于 k k k”呢,只需要第一层循环令 k k k 1 1 1 n n n递增即可。
那么递推公式: a [ i ] [ j ] = m i n ( a [ i ] [ j ] , a [ i ] [ k ] + a [ k ] [ j ] ) a[i][j]=min(a[i][j], a[i][k]+a[k][j]) a[i][j]=min(a[i][j],a[i][k]+a[k][j])

具体讲解可参考我们班主任特特彭老师的教案真叫一个完美


AC代码

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0x3f3f3f3f, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
int a[111][111];
struct edge
{
    int x,y,val;
    edge(int a,int b,int c){x=a,y=b,val=c;}
    edge(){}
};
edge path[1010];
int main()
{
    mem(a); // 初始值是“无穷大”
    int n,m;
    cin>>n>>m;
    fi(i,0,m) // for (int i = 0; i < m; i++)
    {
        int x,y,val;
        cd(x),cd(y),cd(val); // scanf
        a[x][y]=a[y][x]=val;
        path[i]=edge(x,y,val); // 记录下每一条边
    }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(i==j||i==k||j==k);
                else a[i][j]=min(a[i][j], a[i][k]+a[k][j]);
    int ans=0;
    for(int i=0;i<m;i++) // 遍历Tisfy给定的每一条边
    {
        if(a[path[i].x][path[i].y]<path[i].val) // 如果这条边连接的两点的最短路径小于这条边
            ans++; // 那么就说明这条边不在最短路径上
    }
    cout<<ans<<endl;
    return 0;
}

原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/120227579

以上是关于2021-2022-1 ACM集训队每周程序设计竞赛 - 问题 D: 跑图 - 题解的主要内容,如果未能解决你的问题,请参考以下文章

BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛(10)题解

BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛题解

BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛题解

BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛题解

2021-2022-1 ACM集训队每周程序设计竞赛题解

2021-2022-1 ACM集训队每周程序设计竞赛题解