• [10.4模拟赛]T2


    Description

    现有一个(n)个点,(m)条无向边的图。要求求出从编号为(1)的点到编号为(n)的点经过的边的边权的绝对值之和最小的路径。特别的,每经过一条边,图上所有边的边权就会改变,若原边权为(x),新的边权是(frac{1}{1-x})
    答案保留(3)位小数

    Input

    第一行两个整数(m)(n),表示点数和边数。
    接下来(m)行,每行三个整数(u)(v)(x),表示有一条连接(u)(v),边权为(x)

    Output

    (1)(n)联通,输出最小的边权的绝对值之和
    否则输出"chu ti ren shi zhi zhang"(没有引号)。

    Sample Input

    3 1
    2 3 2

    Sample Output

    chu ti ren shi zhi zhang

    Data Constraint

    对于(30)%的数据,(n<=500),(m<=3000)
    对于(100)%的数据,(n<=100000)(m<=300000)(2<=x<=1000)

    Solution

    对于(frac{1}{1-x})这个式子,我们要记住它有一些性质,给一个数(x)
    (x->frac{1}{1-x}->1-frac{1}{x}->x),所以这个数经过(3)次变换之后就会变回原样
    我们把每个点拆成(3)个点,连边,跑一下最短路,就好了

    Code

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    using namespace std;
    #define eps 0.00001
    #define MAXN 5000100
    struct rec {
    	int nxt, ver;
    	double dis;
    } t[MAXN];
    struct Rec {
    	int k;
    	double w;
    };
    bool operator < (const Rec &x, const Rec &y) {
    	return x.w > y.w;
    }
    int n, m, u, v, x, cnt;
    int head[MAXN];
    bool flag[MAXN];
    Rec s;
    priority_queue <Rec> h;
    inline int read() {
    	int s = 0, w = 1;
    	char c = getchar();
    	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
    	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
    	return s * w;
    }
    inline void add(int u, int v, double w) {
    	t[++cnt].nxt = head[u], t[cnt].ver = v, t[cnt].dis = w, head[u] = cnt;
    }
    int main() {
    	freopen("pb.in", "r", stdin);
    	freopen("pb.out", "w", stdout);
    	n = read(), m = read();
    	for (register int i = 1; i <= m; i++) {
    		u = read(), v = read(), x = read();
    		double w = x;
    		add(u, v + n, fabs(w)), add(v, u + n, fabs(w));
    		add(u + n, v + 2 * n, fabs(1 / (1 - w))), add(v + n, u + 2 * n, fabs(1 / (1 - w)));
    		add(u + 2 * n, v, fabs(1 - 1 / w)), add(v + 2 * n, u, fabs(1 - 1 / w));
    	}
    	h.push((Rec){1, 0});
    	while (!h.empty()) {
    		s = h.top();
    		h.pop();
    		if (flag[s.k]) continue;
    		flag[s.k] = true;
    		if (s.k == n || s.k == 2 * n || s.k == 3 * n) break;
    		for (register int i = head[s.k]; i; i = t[i].nxt) {
    			int v = t[i].ver;
    			if (!flag[v])
    				h.push((Rec){v, s.w + t[i].dis});
    		}
    	}
    	if (s.w <= eps) printf("chu ti ren shi zhi zhang");
    	else printf("%.3f", s.w);
    	return 0;
    }
    
    只要有想见的人,就不是孤身一人了。
  • 相关阅读:
    JavaScript DOM 编程艺术(第2版)读书笔记(3)
    JavaScript DOM 编程艺术(第2版)读书笔记(1)
    css杂记
    2020年11月15日
    2020年11月14日
    2020年11月13日
    2020年11月12日
    《代码大全》阅读笔记04
    2020年11月11日
    2020年11月10日
  • 原文地址:https://www.cnblogs.com/Agakiss/p/11621944.html
Copyright © 2020-2023  润新知