zoukankan      html  css  js  c++  java
  • K 短路

    这种东西到现在才学……

    考虑 (T) 为根的最短路树,一条路径一定是树上边和非树边交错。

    我们只管非树边,对于一条路径,非树边构成一个序列 (L),相邻两条路径 (left(u_1,v_1 ight))(left(u_2,v_2 ight)) 显然一定满足 (u_2)(v_1) 的祖先。

    有了这个性质,我们可以解决这个问题。

    考虑最后一条边的转移。要么是转移到答案,即 (dis_u + val + dis_v),要么再选择一条边转移,即 (dis_u' = dis_u + val + dis_{u,v}),其中 (v) 是下一条边的 (u) 的最近祖先端点。

    显然可以用堆维护。由于答案是两个转移式结合,显然还是太繁了。不如直接把所有边权改为 (val' = val + dis_v - dis_u),那么显然经过一条边只是最短路的增量。

    每次一条边的转移直接把距离加上 (val') 即可。

    调试的时候把最短路数组和左偏树数组混用了 /px

    #include <bits/stdc++.h>
    
    const int MAXN = 5010;
    const int MAXE = 200010;
    const int MAXP = 2000000;
    const double eps = 1e-6;
    int n, m;
    int xs[MAXE], ys[MAXE];
    double vs[MAXE], E, dis[MAXN];
    std::vector<int> G[MAXN], el[MAXN];
    inline bool eq(double x) { return -eps < x && x < eps; }
    struct node {
    	int to, ls, rs; double val;
    } tree[MAXP];
    int tot;
    int dx[MAXP];
    int merge(int x, int y) {
    	if (!x || !y) return x | y;
    	if (tree[x].val > tree[y].val) std::swap(x, y);
    	int now = ++tot; node & t= tree[now] = tree[x];
    	t.rs = merge(t.rs, y);
    	if (dx[t.ls] < dx[t.rs]) std::swap(t.ls, t.rs);
    	dx[now] = dx[t.rs] + 1;
    	return now;
    }
    void shortestpath() {
    	for (int i = 1; i <= m; ++i)
    		G[ys[i]].push_back(i);
    	for (int i = 0; i < n; ++i)
    		dis[i] = 1e20;
    	dis[n] = 0;
    	static bool vis[MAXN];
    	for (int i = 1; i <= n; ++i) {
    		int at = 0;
    		for (int j = 1; j <= n; ++j)
    			if (!vis[j] && dis[j] < dis[at])
    				at = j;
    		vis[at] = true;
    		const int SZ = G[at].size();
    		for (int j = 0; j != SZ; ++j) {
    			int u = G[at][j];
    			dis[xs[u]] = std::min(dis[xs[u]], dis[at] + vs[u]);
    		}
    	}
    	memset(vis, 0, n + 1);
    	for (int i = 1; i <= n; ++i) G[i].clear();
    	for (int i = 1; i <= m; ++i)
    		if (eq(-dis[xs[i]] + dis[ys[i]] + vs[i]))
    			if (!vis[xs[i]]) {
    				vis[xs[i]] = true;
    				G[ys[i]].push_back(xs[i]);
    			}
    	for (int i = 1; i <= m; ++i)
    		el[xs[i]].push_back(i);
    }
    int rt[MAXN];
    void dfs(int u, int fa = 0) {
    	rt[u] = rt[fa];
    	const int LZ = el[u].size();
    	bool fir = false;
    	for (int i = 0; i != LZ; ++i) {
    		int at = el[u][i];
    		double v = dis[ys[at]] + vs[at] - dis[u];
    		if (v < eps && !fir) { fir = true; continue; }
    		++tot;
    		tree[tot].to = ys[at];
    		tree[tot].val = v;
    		rt[u] = merge(rt[u], tot);
    	}
    	const int SZ = G[u].size();
    	for (int i = 0; i != SZ; ++i)
    		dfs(G[u][i], u);
    }
    struct qs {
    	int rt; double v;
    	bool operator < (const qs & b) const {
    		return v > b.v;
    	}
    } ;
    std::priority_queue<qs> q;
    qs trans(int rt, double v) {
    	qs res;
    	res.rt = rt, res.v = v + tree[rt].val;
    	return res;
    }
    int main() {
    	std::ios_base::sync_with_stdio(false), std::cin.tie(0);
    	std::cin >> n >> m >> E;
    	for (int i = 1; i <= m; ++i)
    		std::cin >> xs[i] >> ys[i] >> vs[i];
    	shortestpath();
    	dfs(n);
    	++tot; tree[tot].to = 1;
    	tree[tot].val = dis[1];
    	q.push(trans(tot, 0));
    	int ans = 0;
    	while (true) {
    		qs x = q.top(); q.pop();
    		E -= x.v;
    		if (E + eps <= 0) break;
    		++ans;
    		if (int t = rt[tree[x.rt].to])
    			q.push(trans(t, x.v));
    		x.v -= tree[x.rt].val;
    		x.rt = merge(tree[x.rt].ls, tree[x.rt].rs);
    		if (x.rt) q.push(trans(x.rt, x.v));
    	}
    	std::cout << ans << std::endl;
    	return 0;
    }
    
  • 相关阅读:
    Delphi / C++ Builder 使用 UDT ( UDP-based Data Transfer ) 4.11
    STUN: NAT 类型检测方法
    udt nat traverse
    UDT: Breaking the Data Transfer Bottleneck
    Freescale OSBDM JM60仿真器
    How To: Perl TCP / UDP Socket Programming using IO::Socket::INET
    NAT类型与穿透 及 STUN TURN 协议
    根据PID和VID得到USB转串口的串口号
    pic/at89c2051 programmer
    IC开短路测试(open_short_test),编程器测试接触不良、开短路
  • 原文地址:https://www.cnblogs.com/daklqw/p/11681336.html
Copyright © 2011-2022 走看看