zoukankan      html  css  js  c++  java
  • 求权值的积最小 题解

    原题点这里

    题目描述

    给定 (n) 个点的带权有向图,求从 (1)(n) 的路径中边权之积最小的简单路径。

    • 输入格式 第一行读入两个整数 (n)(m),表示共 (n) 个点 (m) 条边。 接下来 (m) 行,每行三个正整数 (x,y,z),表示点 (x) 到点 (y) 有一条边权为 (z) 的边。

    • 输出格式 输出仅包括一行,记为所求路径的边权之积,由于答案可能很大,因此哥输出它模 998799879987 的余数即可。

    样例输入

    3 3
    1 2 3 
    2 3 3 
    1 3 10
    

    样例输出

    9
    

    分析

    乍一看,这道题就只是个最短路而已,这道题的难点主要在于如何维护取模后的值。
    最后发现模好像会炸,高精好像也会炸。。。
    所以我们就……
    引入对数!


    对数的性质 (log(mn)=log(m)+log(n))
    其证明:
    我们以 (log_2)为例子,(log_2(n)) 表示方程 (2^x=n)(x) 的解。令(2^x=n,2^y=m)

    首先 (x+y=x+y)
    所以 (log_2(2^ x*2^y)=x+y)
    (log_2(2^ x*2^y)=log_2(2^x)+log_2(2^y))
    则可得到对数的性质:(log(mn)=log(m)+log(n))
    加入最短路优化即可。。。

    AC代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    const int INF = 0x3F3F3F3F;
    const int MAXN = 1005;
    const int mod = 9987;
    double dist[MAXN];
    int cost[MAXN][MAXN], pre[MAXN][2];
    bool vis[MAXN];
    int n, m;
    
    void Di_Set(int s) {
        for (int i = 0; i <= n; ++i) dist[i] = 1e9;
        memset(vis, 0, sizeof vis);
        dist[s] = 0;
        for (int i = 1; i <= n; i++) {
            int mi = INF, k;
            for (int j = 1; j <= n; j++) {  //蓝点集 路程最小值
                if (!vis[j] && dist[j] < mi) {
                    mi = dist[j];
                    k = j;
                }
            }
            vis[k] = true;                  //加入红点集
            for (int j = 1; j <= n; j++) {  // 更新相连的
                if (cost[k][j] > 0 && dist[k] + log(cost[k][j]) < dist[j]) { 
                //在这个时候就直接用对数进行计算
                    dist[j] = dist[k] + log(cost[k][j]);
                    pre[j][0] = k;
                    pre[j][1] = cost[k][j];
                }
            }
        }
    }
    
    int main() {
        scanf("%d %d", &n, &m);
        for (int i = 1; i <= m; i++) {
            int u, v, x;
            scanf("%d %d %d", &u, &v, &x);
            cost[u][v] = x;
        }
        Di_Set(1);  //调用
        int ans = 1;
        int pos = n;
        while (pos != 1) { //从对数转正确答案
            ans *= pre[pos][1];
            ans %= mod;
            pos = pre[pos][0];
        }
        printf("%d", ans);
        return 0;
    }
    
  • 相关阅读:
    我爱Java系列之---【SpringBoot打成war包部署】
    279. Perfect Squares
    矩阵dfs--走回路
    112. Path Sum
    542. 01 Matrix
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    Invert Binary Tree
    563 Binary Tree Tilt
    145 Binary Tree Postorder Traversal
  • 原文地址:https://www.cnblogs.com/Chain-Forward-Star/p/13868104.html
Copyright © 2011-2022 走看看