SZY 的旅行 题解

image

将图按照邻接矩阵存为一个矩阵,则有性质为:该矩阵的 \(k\) 次方反映了 在该图上恰好走 \(k\) 次的可达性。

有了这条性质可以按边权将所有边排序,在图上动态加入能新走的边,用矩阵快速幂处理出当前图恰好走这条边边权次的可达性矩阵。每新加入一条边,用 floyd 求出加入这条边影响后新的最短路。

code:

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define debug cout<<"DEBUG"<<endl;
#define pb push_back
#define pii pair<int,int>
#define vi vector<int>
#define imp map<int,int>
using namespace std;
const int N=155; 
int n,m;
ll ans=1e18,dis[N][N];
struct EDGE{
	int from,to;
	ll c;
}e[N];
struct Matrix{
	bitset<N>a[N];
	Matrix(){
		for(int i=0;i<N;i++) a[i].reset();
	}
	void clear(){
		for(int i=0;i<N;i++){
			a[i].reset();
		}
	}
	friend Matrix operator * (Matrix A,Matrix B){
        Matrix ans;
		ans.clear();
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(A.a[i][j]) ans.a[i]|=B.a[j];
            }
        }
		return ans;
    }
}now,bas;
bool cmp(EDGE A,EDGE B){
	return A.c<B.c;
}
Matrix qpow(Matrix x,int y){
	Matrix prod;
	prod.clear(); 
	for(int i=1;i<=n;i++){
		prod.a[i][i]=1;
	}
	while(y>0){
		if(y&1) prod=prod*x;
		y>>=1;
		x=x*x;
	}
	return prod;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int x,y;
		ll z;
		scanf("%d%d%lld",&x,&y,&z);
		e[i].from=x,e[i].to=y,e[i].c=z;
	} 
    now.clear(),bas.clear();
	memset(dis,0x3f,sizeof(dis));
	for(int i=1;i<=n;i++){
		dis[i][i]=0;
		now.a[i][i]=1;
	}
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=m;i++){
		now=now*qpow(bas,e[i].c-e[i-1].c);
		for(int j=1;j<=n;j++)
			for(int k=1;k<=n;k++)
				dis[j][k]=min(dis[j][k],dis[j][e[i].from]+dis[e[i].to][k]+1);
		for(int j=1;j<=n;j++){
			if(!now.a[1][j]) continue;
			ans=min(ans,e[i].c+dis[j][n]);
		}
		bas.a[e[i].from][e[i].to]=1;
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2023-10-14 17:20  Aurora_Borealis  阅读(10)  评论(0编辑  收藏  举报