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

题目链接

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

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

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

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

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

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

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

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;
}

利用 TensorFlow 训练自己的目标识别器。本文内容来自于我的毕业设计,基于 TensorFlow 1.15.0,其他 TensorFlow 版本运行可能存在问题。.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值