• 【题解】牛继电器Cow Relays


    查看原题请戳这里

    首先,我们要明确这里的最短路是在经过n条路径的前提下的最短路,因为这是无向图,所以一定有解。

    我们先来看朴素的Floyd的代码:

    for(int k = 1; k <= n; k++)
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= n; j++)
    			f[i][j] = min(f[i][j],f[i][k] + f[k][j]);
    

    其中,我们每次都是枚举k并用ta去当中转点去更新每一个i->j的最短路。

    那么,当k等于n/2时这段代码完成了什么呢?

    那就是我们尝试了用[1,n/2]的点去更新最短路,我们可以发现,这样得到的最短路最多包含k+1条路径。

    为什么是最多k+1条呢?

    因为我们每次用k去尝试更新i->j的最短路是不一定成功(即f[i][j]<=f[i][k]+f[k][j])

    所以我们可以用Floyd+dp+倍增去切掉这道题

    我们再来看一下矩阵乘法的代码:

    for(int k = 1; k <= n; k++)
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= n; j++)
    			c[i][j] = c[i][j] + a[i][k] * b[k][j];
    

    是不是和Floyd的代码有点相似?

    因为我们要求的是最短路,所以我们要对这个矩阵乘法魔改一下:

    memset(c,0x7f,sizeof(c));
    for(int k = 1; k <= n; k++)
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= n; j++)
    			c[i][j] = min(c[i][j],a[i][k] + a[k][j]);
    

    是不是和Floyd越来越相似了……

    但是在这里,c[i][j]的初值为INF,所以我们每次枚举k都会选择一条边去更新最短路,所以如果我们用邻接矩阵map(不是STL的那个map)去存边,那么map的n次方存的就是经过n条边的最短路。

    code:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    #define INF 0x7fffffff
    #define re register
    #define rep(i,a,b) for(int i = (a); i <= (b); i++)
    #define qwq printf("qwq
    ");
    
    using namespace std;
    
    long long read()
    {
    	register long long x = 0,f = 1;register char ch;
    	ch = getchar();
    	while(ch > '9' || ch < '0'){if(ch == '-') f = -f;ch = getchar();}
    	while(ch <= '9' && ch >= '0'){x = x * 10 + ch - 48;ch = getchar();}
    	return x * f;
    }
    
    
    long long n,m,t,sta,End,cnt,siz,u,d[100005];
    
    struct edge{
    	int fro,to,l;
    }e[100005];
    
    struct juzhen{
    	long long a[105][105];
    	juzhen operator * (const juzhen &x) const
        {
            juzhen c;
            memset(c.a,0x7f,sizeof(c.a));
            for(int k = 1; k <= siz; k++)
                for(int i = 1; i <= siz; i++)
                    for(int j = 1; j <= siz; j++)
                        c.a[i][j] = min(c.a[i][j],a[i][k]+x.a[k][j]);
            return c;       
        }
    }ans,map; 
    
    void ksm(int b)
    {
    	while(b > 0)
    	{
    		if(b & 1) ans = ans * map;
    		map = map * map;
    		b >>= 1;
    	}
    }
    
    bool cmp(int a,int b){return a < b;}
    
    int main()
    {
    	n = read(); m = read(); sta = read(); End = read();
        for(int i = 1; i <= m; i++)
        {
        	e[i].l = read(); e[i].fro = read(); e[i].to = read();
        	d[++cnt] = e[i].fro; d[++cnt] = e[i].to;
    	}
    	sort(d + 1, d + cnt + 1, cmp);
    	siz = unique(d + 1, d + cnt + 1) - d - 1;
    	for(int i = 1; i <= siz; i++)
    		for(int j = 1; j <= siz; j++)
    			map.a[i][j] = INF;
      	for(int i = 1; i <= m; i++)
    	{
    		e[i].fro = lower_bound(d + 1, d + siz + 1, e[i].fro) - d;
    		e[i].to = lower_bound(d + 1, d + siz + 1, e[i].to) - d;
    		map.a[e[i].fro][e[i].to] = e[i].l;
    		map.a[e[i].to][e[i].fro] = e[i].l;
    	}
    	sta = lower_bound(d + 1, d + siz + 1, sta) - d;
    	End = lower_bound(d + 1, d + siz + 1, End) - d;// li san hua 
    	for(int i = 1; i <= siz; i++)
    		for(int j = 1; j <= siz; j++)
    			ans.a[i][j] = map.a[i][j];
    	ksm(n - 1);
    	printf("%d
    ",ans.a[sta][End]);
        return 0;
    }
    
    
  • 相关阅读:
    Model, View(Camera), Perspective (1)
    流状态和c++的异常处理
    VAO VBO EBO(3)
    VAO VBO EBO(2)
    VAO VBO EBO(1)
    函数指针(2)
    函数指针
    内联函数和宏函数的一些区别
    关于宏的一些知识
    关于未来方向
  • 原文地址:https://www.cnblogs.com/aurorapolaris/p/13449112.html
Copyright © 2020-2023  润新知