欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

河南第十届ACM省赛-I-Transmit information

程序员文章站 2024-03-22 14:00:04
...

ACM模版

描述

河南第十届ACM省赛-I-Transmit information

题解

十分有趣的一道题,可以用 dp 解,也可以用倍增法 Floyd 解,标程是后者。

这里是求经过 N 条边的最短路,简单的最短路算法已经无法满足需求,我们需要对图进行 N 次 Floyd,由于每次 Floyd 都不是直接对原花费矩阵操作,而是将值存在另一个矩阵中,所以可以保证每次 Floyd 都能够只收缩一条边,这样 N 次 Floyd 后就能保证通过了 N 条边获取的最短路。这里由于 Floyd 是 O(n3) 复杂度,所以进行 N 次 Floyd 显然是不现实的,这里我们可以利用矩阵快速幂的思路搞矩阵加速,这样就使其变为可行了。最后总复杂度为 O(n3logn),客观讲,这个解法不难理解,但是没有接触过的真是不好想到,具体代码十分容易看明白,就不多说了。

代码

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>

using namespace std;

const int MAXN = 1005;

int k, m, s, t;
int ans[MAXN][MAXN];
int tmp[MAXN][MAXN];
int tmp_[MAXN][MAXN];
int used[MAXN], v[MAXN], cnt;

void floyd(int c[][MAXN], int a[][MAXN], int b[][MAXN])
{
    for (int k = 0; k < cnt; k++)
    {
        for (int i = 0; i < cnt; i++)
        {
            for (int j = 0; j < cnt; j++)
            {
                if (c[v[i]][v[j]] > a[v[i]][v[k]] + b[v[k]][v[j]])
                {
                    c[v[i]][v[j]] = a[v[i]][v[k]] + b[v[k]][v[j]];
                }
            }
        }
    }
}

void copy(int a[][MAXN], int b[][MAXN])
{
    for (int i = 0; i < cnt; i++)
    {
        for (int j = 0; j < cnt; j++)
        {
            a[v[i]][v[j]] = b[v[i]][v[j]];
        }
    }
}

void slove(int k)
{
    while (k)
    {
        if (k & 1)
        {
            floyd(tmp_, ans, tmp);
            copy(ans, tmp_);
            memset(tmp_, 0x3f, sizeof(tmp_));
        }
        floyd(tmp_, tmp, tmp);
        copy(tmp, tmp_);
        memset(tmp_, 0x3f, sizeof(tmp_));
        k >>= 1;
    }
}

void init()
{
    cnt = 0;
    memset(tmp, 0x3f, sizeof(tmp));
    memset(tmp_, 0x3f, sizeof(tmp_));
    memset(ans, 0x3f, sizeof(ans));
    for (int i = 0; i < MAXN; i++)
    {
        ans[i][i] = 0;
    }
}

int main()
{
    init();

    scanf("%d%d%d%d", &k, &m, &s, &t);

    int x, y, w;
    for (int i = 0; i < m; i++)
    {
        scanf("%d%d%d", &w, &x, &y);
        if (!used[x])
        {
            used[x] = 1;
            v[cnt++] = x;
        }
        if (!used[y])
        {
            used[y] = 1;
            v[cnt++] = y;
        }
        if (tmp[x][y] > w)
        {
            tmp[x][y] = tmp[y][x] = w;
        }
    }

    slove(k);

    printf("%d\n", ans[s][t]);

    return 0;
}