洛谷2886 [USACO07NOV]牛继电器Cow Relays (矩阵乘法+Floyd)

题目链接

一道很有纪念意义的题目啊qwq
感觉其实还不是很理解。

首先,根据题目的数据范围,我们可以想到用 f l o y d floyd 去解决这个问题。

我们会发现,假设我们已经知道了一个经过 x x 条路,到某个点的最短路矩阵 a a ,同时我们知道了每个点出发经过一条路到各个点的最短路矩阵 b b ,我们令 c [ i ] [ j ] = m i n ( c [ i ] [ j ] , a [ i ] [ k ] + b [ k ] [ j ] ) c[i][j]=min(c[i][j],a[i][k]+b[k][j]) ,新得到的矩阵,就应该对应的是经过 x + 1 x+1 条路径到每个点的最短路。

那我们貌似可以通过 k k 次暴力合并,来得到答案。但显然这样的复杂度是不够优秀的。

经过观察,我们发现这个过程很像是两个矩阵在进行矩阵乘法(一种变形)。

那么我们可以直接选择矩阵快速幂来优化这个过程。然后就可以把复杂度变到比较优秀的复杂度辣!

但是需要注意的一个小 t i p s tips 是,我们可以令初始的 a n s ans 等于一开始的 d i s dis 矩阵,然后只需要和 k 1 k-1 次方的矩阵合并即可。

QWQ
感觉细节还是很多啊

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
#define int long long
#define pb push_back
using namespace std;
inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}
const int maxn = 210;
struct Ju{
	int x,y;
	int a[maxn][maxn];
	Ju operator* (Ju b)
	{
		Ju ans;
		ans.x=x;
		ans.y=b.y;
		memset(ans.a,127/3,sizeof(ans.a));
		for (int k=1;k<=y;k++)
	  	  for (int i=1;i<=ans.x;i++)
		    for (int j=1;j<=ans.y;j++)
		      ans.a[i][j]=min(ans.a[i][j],a[i][k]+b.a[k][j]);
		return ans;
	}
};
Ju dis;
Ju qsm(Ju i,int j)
{
    Ju ans = i;
    while (j)
    {
  	  if (j&1) ans=ans*i;
      i=i*i;	
	  j>>=1;
    }
    return ans;
}
int tot;
int x[maxn],y[maxn],w[maxn];
int n,m;
vector<int> v;
int k;
int s,t;
int getnum(int val)
{
	return lower_bound(v.begin(),v.end(),val)-v.begin()+1;
}
signed main()
{
  k=read();
  m=read();
  s=read(),t=read();
  v.pb(s);
  v.pb(t);
  for (int i=1;i<=m;i++)
  {
  	w[i]=read(),x[i]=read(),y[i]=read();
  	v.pb(x[i]);
  	v.pb(y[i]);
  } 
  sort(v.begin(),v.end());
  n=unique(v.begin(),v.end())-v.begin();
  v.resize(n);
  n++;
  s=getnum(s);
  t=getnum(t);
  memset(dis.a,0x3f,sizeof(dis.a));
  //for(int i=1;i<=n;i++) dis.a[i][i]=0;
  dis.x=n;
  dis.y=n;
  for (int i=1;i<=m;i++)
  {
  	x[i]=getnum(x[i]);
  	y[i]=getnum(y[i]);
  	dis.a[x[i]][y[i]]=min(dis.a[x[i]][y[i]],w[i]);
  	dis.a[y[i]][x[i]]=dis.a[x[i]][y[i]];
  }
  dis=qsm(dis,k-1);
  cout<<dis.a[s][t]<<endl;
  return 0;
}

猜你喜欢

转载自blog.csdn.net/y752742355/article/details/85054352