码迷,mamicode.com
首页 > Windows程序 > 详细

AcWing 牛站

时间:2019-08-20 01:13:56      阅读:109      评论:0      收藏:0      [点我收藏+]

标签:总结   main   mem   pow   eof   str   esc   次方   win   

AcWing 牛站

Description

  • 给定一张由T条边构成的无向图,点的编号为1~1000之间的整数。

    求从起点S到终点E恰好经过N条边(可以重复经过)的最短路。

Input

  • 第1行:包含四个整数N,T,S,E。

    第2..T+1行:每行包含三个整数,描述一条边的边长以及构成边的两个点的编号。

Output

  • 输出一个整数,表示最短路的长度。

Sample Input

2 6 6 4
11 4 6
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9

Sample Output

10

Data Size

10

题解:

  • 矩阵快速幂。
  • 挺妙的一道题。当我们设A(i, j)为i到j经过0条边的最短路。那么显然原图的邻接矩阵就是A矩阵,我们再设B(i, j)为i到j经过1条边的最短路。 那么我们只需要枚举中间点k,然后在A矩阵中进行松弛即可。那么A矩阵枚举一次中转点得到B矩阵。那么我要求经过N条道的矩阵。那么不就是A矩阵枚举N次中转点吗?即A矩阵的N次方次运算。但是,矩阵乘法中发生了变动,即变成了类似Floyd的东西,因为要求最短路。你可能会问,为什么快速幂又不用变呢?快速幂只是保证进行运算的次数。
  • 那么枚举中转点后,如果更新呢?举个例子,假设现在有4个点1、2、3、4。现要更新2到1的最短路。我们可以看看dis(2, 1) + dis(1, 1)是否 < dis(1, 2);dis(2, 2) + dis(2, 1)是否 < dis(1, 2);dis(2, 3) + dis(3, 1)是否 < dis(1, 2);dis(2, 4) + dis(4, 1)是否 < dis(1, 2)。那么放在矩阵中看,刚好就是矩阵A和矩阵A进行运算的位置(2, 1)的结果。所以可以用矩阵乘法的运算法则去算,算的内容用松弛操作。
  • 总结:进行N次运算,一次运算的定义是枚举中转点进行松弛操作,运算的实现用矩阵乘法的运算法则和Floyd的思想实现。

  • 代码细节:原图时(i, i)不能置为0。因为我可以问你从1点到1点经过5条道路的最短路是多少(显然不是0

#include <iostream>
#include <cstdio>
#include <cstring>
#define N 205
using namespace std;

struct A
{
    int m[N][N];
    A() {memset(m, 0x3f, sizeof(m));}
} a;
struct E {int u, v, w;} e[N];
int k, m, sta, en, n;
int b[N], f[1000005];

A mul(A x, A y)
{
    A z;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            for(int k = 1; k <= n; k++)
                z.m[i][j] = min(z.m[i][j], x.m[i][k] + y.m[k][j]);
    return z;
}

A power(A a, int b)
{
    A r = a, base = a;
    while(b)
    {
        if(b & 1) r = mul(r, base);
        base = mul(base, base);
        b >>= 1;
    }
    return r;
}

int main()
{
    cin >> k >> m >> sta >> en;
    for(int i = 1; i <= m; i++)
    {
        cin >> e[i].w >> e[i].u >> e[i].v;
        if(!f[e[i].u]) f[e[i].u] = ++n;
        if(!f[e[i].v]) f[e[i].v] = ++n;
    }
    for(int i = 1; i <= m; i++)
    {
        int u = f[e[i].u], v = f[e[i].v];
        a.m[u][v] = a.m[v][u] = min(a.m[v][u], e[i].w);
    }
    a = power(a, k - 1);
    cout << a.m[f[sta]][f[en]];
    return 0;
}

AcWing 牛站

标签:总结   main   mem   pow   eof   str   esc   次方   win   

原文地址:https://www.cnblogs.com/BigYellowDog/p/11380623.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!