• AcWing 345. 牛站 Cow Relays


    由于我太菜了,不会矩阵乘法,所以给同样不会矩阵乘法同学的福利

    首先发现这题点很多边很少,实际上有用的点 (<= 2 * T)(因为每条边会触及两个点嘛)

    所以我们可以把点的范围缩到 (2 * T)来,然后...

    算法1 Bellman - Ford O(NT)

    什么,限制边数?那不就是可爱的 (BellmanFord)吗?

    看看复杂度,嗯嗯 (10 ^ 8) 海星,常数超小的我肯定不用吸氧的

    #pragma GCC optimize(2)
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    using namespace std;
    const int N = 205, M = 105;
    struct Edge{
    	int u, v, w;
    }e[M];
    int m, n, s, t, adj[N], dis[N], bDis[N], tot;
    void inline read(int &x) {
        x = 0;
        char s = getchar();
        while(s > '9' || s < '0') s = getchar();
        while(s <= '9' && s >= '0') x = x * 10 + s - '0', s = getchar();
    }
    int inline get(int &x) {
    	return lower_bound(adj + 1, adj + 1 + tot, x) - adj;
    }
    
    int inline bellmanFord(){
        memset(dis, 0x3f, sizeof dis);
        dis[s] = 0;
        for(register int i = 1; i <= n; i++){
            memcpy(bDis, dis, sizeof dis);
            memset(dis, 0x3f, sizeof dis);
            for(register int j = 1; j <= m; j++){
                dis[e[j].v] = min(dis[e[j].v], bDis[e[j].u] + e[j].w);
                dis[e[j].u] = min(dis[e[j].u], bDis[e[j].v] + e[j].w);
            }
        }
        return dis[t];
    }
    
    
    
    int main(){
    	read(n); read(m); read(s); read(t);
    	for (register int i = 1; i <= m; i++) {
    		read(e[i].w); read(e[i].u); read(e[i].v);
    		adj[++tot] = e[i].u;
    		adj[++tot] = e[i].v;
    	}
    	sort(adj + 1, adj + 1 + tot);
    	tot = unique(adj + 1, adj + 1 + tot) - adj - 1;
    	for (register int i = 1; i <= m; i++) {
    		e[i].u = get(e[i].u), e[i].v = get(e[i].v);
    	}
    	s = get(s), t = get(t);
    	printf("%d
    ", bellmanFord());
    	return 0;
    }
    

    真香

    算法2 倍增 + Floyd O(T ^ 3 * log_2N)

    据说这题正解要用矩阵乘法,可我不会,咋办呢?

    不如用倍增的思想,把(N)拆成二进制下的多个(1),我们把每个('1')最短路搞出来,然后拼出来最终的最短路,先预处理:

    (d[i][j][l]) 表示从 (i)(j) 恰好经过 (2 ^ l) 条边的最短路。

    初始化 (d[i][j][0] = w[i][j]),剩下为正无穷(注意是恰好 (N) 条边,所以 (d[i][i][0]) 也是非法状态)

    转移也很好想:

    (d[i][j][l] = min(d[i][k][l - 1] + d[k][j][l - 1])),对于一个状态 (d[i][j][l]),枚举中间点 (k) 即可,所以预处理复杂度 (O(T ^ 3 * log_2N))

    接下来用二进制拼起来就行辣~,设 (g[i]) 为这前几部走完后,从 (s)(i) 的最短路, (f[i]) 为当前到 (i) 的最短路,与保卫王国的拼凑法思想差不多,即:

    (f[i] = min(g[j] + d[j][i][c]))(N) 的二进制第 (c) 位为 (1)

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    using namespace std;
    const int N = 205, M = 105;
    struct Edge{
    	int u, v, w;
    }e[M];
    int m, n, s, t, adj[N], tot, d[N][N][20], f[N], g[N];
    int L;
    
    int inline get(int x) {
    	return lower_bound(adj + 1, adj + 1 + tot, x) - adj;
    }
    int main(){
    	memset(d, 0x3f, sizeof d);
    	scanf("%d%d%d%d", &n, &m, &s, &t);
    	L = log2(n);
    	for (int i = 1; i <= m; i++) {
    		scanf("%d%d%d", &e[i].w, &e[i].u, &e[i].v);
    		adj[++tot] = e[i].u;
    		adj[++tot] = e[i].v;
    	}
    	sort(adj + 1, adj + 1 + tot);
    	tot = unique(adj + 1, adj + 1 + tot) - adj - 1;
    	for (int i = 1; i <= m; i++) {
    		int u = get(e[i].u), v = get(e[i].v), w = e[i].w;
    		d[u][v][0] = d[v][u][0] = min(d[u][v][0], w);
    	}
    	s = get(s), t = get(t);
    	
    	for (int c = 1; c <= L; c++) {
    		for (int i = 1; i <= tot; i++) {
    			for (int j = 1; j <= tot; j++) {
    				for (int k = 1; k <= tot; k++) {
    					d[i][j][c] = min(d[i][j][c], d[i][k][c - 1] + d[k][j][c - 1]);
    				}
    			}
    		}
    	}
    	
    	memset(g, 0x3f, sizeof g);
    	g[s] = 0;
    	for (int c = 0; c <= L; c++) {
    		if(n >> c & 1) {
    			memset(f, 0x3f, sizeof f);
    			for (int i = 1; i <= tot; i++) 
    				for (int j = 1; j <= tot; j++)
    					f[i] = min(f[i], g[j] + d[j][i][c]);
    			memcpy(g, f, sizeof g);
    		}
    	}
    	printf("%d
    ", f[t]);
    	return 0;
    }
    
  • 相关阅读:
    MySQL:批量修改表的排序规则
    Python黑客编程3网络数据监听和过滤
    springboot redis 项目实战 完整篇
    C#读取U盘序列号
    AS3,ReferenceError: Error #1056: 无法为 ×× 创建属性 ×××。
    知道挖掘机如何从货车上下来吗?
    一次进销存软件架构的实践(二)——业务外观层设计
    重构你的软件企业
    遇到了火狐扩展全部丢失的问题
    分布式系统设计原理与方案
  • 原文地址:https://www.cnblogs.com/dmoransky/p/11831592.html
Copyright © 2020-2023  润新知