zoukankan      html  css  js  c++  java
  • BZOJ 2306: [Ctsc2011]幸福路径

    Description

    有向图 G有n个顶点 1, 2, …, n,点i 的权值为 w(i)。现在有一只蚂蚁,从
    给定的起点 v0出发,沿着图 G 的边爬行。开始时,它的体力为 1。每爬过一条
    边,它的体力都会下降为原来的 ρ 倍,其中ρ 是一个给定的小于1的正常数。而
    蚂蚁爬到某个顶点时的幸福度,是它当时的体力与该点权值的乘积。
    我们把蚂蚁在爬行路径上幸福度的总和记为 H。很显然,对于不同的爬行路
    径,H 的值也可能不同。小 Z 对 H 值的最大可能值很感兴趣,你能帮助他计算
    吗?注意,蚂蚁爬行的路径长度可能是无穷的。

    Input
    每一行中两个数之间用一个空格隔开。
    输入文件第一行包含两个正整数 n, m,分别表示 G 中顶点的个数和边的条
    数。
    第二行包含 n个非负实数,依次表示 n个顶点权值 w(1), w(2), …, w(n)。
    第三行包含一个正整数 v0,表示给定的起点。
    第四行包含一个实数 ρ,表示给定的小于 1的正常数。
    接下来 m行,每行两个正整数 x, y,表示<x, y>是G的一条有向边。可能有
    自环,但不会有重边。

    Output
    仅包含一个实数,即 H值的最大可能值,四舍五入到小数点后一位。

    Sample Input
    5 5
    10.0 8.0 8.0 8.0 15.0
    1
    0.5
    1 2
    2 3
    3 4
    4 2
    4 5

    Sample Output
    18.0

    题解
    当走无限步时 , 答案会很快到达一个临界值 , 这个值趋于不变 , 因为这个时候的p已经很小了,对答案的贡献很小 , 所以可以设定一个极大的步数 , 求出走完这么多步之后的答案 ,
    考虑倍增floyd , 设(f[t][i][j]) 表示从i出发走了 (2^t) 到达j 的贡献,转移方程是
    (f[t][i][j] = max(f[t][i][j] , f[t-1][i][k] + f[t-1][k][j] * p ^ {2 ^ {t-1}})
    倍增一下就好。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const int N = 110;
    inline int read()
    {
        register int x = 0 , f = 0; register char c = getchar();
        while(c < '0' || c > '9') f |= c == '-' , c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
        return f ? -x : x;
    }
    int n , m , S , cnt;
    double p;
    int head[N];
    double a[N] , f[N][N] , g[N][N] , t[N][N];
    struct edge{ int v , nex; } e[N*10];
    inline void add(int u , int v) { e[++cnt].v = v; e[cnt].nex = head[u]; head[u] = cnt; return ; }
     
    void mul(int K)
    {
        for(int i = 1 ; i <= n ; ++i) for(int j = 1 ; j <= n ; ++j) g[i][j] = t[i][j] = f[i][j] , f[i][j] = -1e8;
        for(int k = 1 ; k <= n ; ++k)  // 我之前居然傻到没有枚举 k……
            for(int i = 1 ; i <= n ; ++i) 
                for(int j = 1 ; j <= n ; ++j) 
                    f[i][j] = max(f[i][j] , g[i][k] + t[k][j] * p);
        return ;
    }
     
    double ksm(int k)
    {
        for(int i = 1 ; i <= k ; ++i) mul(i) , p = p * p;
        double ans = 0;
        for(int i = 1 ; i <= n ; ++i) ans = max(ans , f[S][i]);
        return ans + a[S];
    }
     
    int main()
    {
        n = read(); m = read();
        for(int i = 1 ; i <= n ; ++i) scanf("%lf" , &a[i]);
        S = read(); scanf("%lf" , &p);
        for(int i = 1 ; i <= n ; ++i) for(int j = 1 ; j <= n ; ++j) f[i][j] = (i == j ? 0 : -1e8);  // 没有的要赋成-inf , 要不然就会用本来没有的边 , 更新答案。
        for(int i = 1 , u , v; i <= m ; ++i) u = read() , v = read() , add(u , v) , f[u][v] = a[v] * p;
        printf("%.1f
    " , ksm(30));
        return 0;
    }
    
  • 相关阅读:
    【SSO单点系列】(1):CAS4.0 环境的搭建
    Docker学习总结之Run命令介绍
    使用 RMI + ZooKeeper 实现远程调用框架
    JAVA CAS单点登录(SSO)
    web应用中Spring ApplicationContext的动态更新
    Java 中 String、StringBuffer、StringBuilder 三者之间的区别
    static final 、static 、final 区别
    static Java 关键字 简单理解
    final Java 关键字 深入浅出,简单理解
    进程 线程 简单理解说明
  • 原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12249939.html
Copyright © 2011-2022 走看看