【题解】牛继电器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;
}

原文地址:https://www.cnblogs.com/aurorapolaris/p/13449112.html