*题解:P6190 [NOI Online #1 入门组] 魔法

题目链接

解析

考虑 \(k = 0\) 的情况,是一个裸的最短路,跑一遍 Floyd 即可。

考虑 \(k = 1\) 的情况,我们枚举需要取反边权的边 \(u\to v\),那么取反该边情况下 \(1\)\(n\) 的最短路其实就是 \(1\to u\)\(v \to n\) 两部分最短路和我们取反后的这条边并起来。具体地,设 \(d_{i,j}\) 表示原图中 \(i\)\(j\) 的最短路,\(u,v\) 边权为 \(w\),那么至多取反一次的最短路为 \(f_{i,j} = \min (d_{i,u} -w + d_{v,j})\)

考虑 \(k = 2\) 的情况,可以枚举点然后转化成 \(k = 1\) 的情况,具体地,至多取反两次后的最短路为 \(g_{i,j} = \min(f_{i,x} + f_{x,j})\)

同理,如果设 \(d_{i,u,v}\) 表示至多取反 \(i\) 次之后,\(u\)\(v\) 的最短路,那么对于 \(i > 1\),有:

\[d_{i,u,v} = \min (d_{i - 1,u,x} + d_{1,x,v}) \]

这是 \((\min,+)\) 矩阵乘法的形式,可以进行矩阵加速。

时间复杂度 \(O(n^2m + n^3 \log k)\)

代码

#include <bits/stdc++.h>
#define eps 0.0000000001
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
typedef unsigned ui;
typedef pair<int,int> pii;
const int N = 100 + 5,M = 20,P = 2000000,mod = 998244353,mod2 = 1e9 + 7,b1 = 131,b2 = 13331; 
ll d[N][N];
struct Edge{
	int u,v;
	ll w;
};
vector<Edge> e;
struct Mtx{
	ll m[N][N];
	int row,col;
	Mtx (int r,int c) : row(r),col(c){
		for(int i=1;i<=row;i++){
			for(int j=1;j<=col;j++){
				m[i][j] = 1e18;
			}
		}
	} 
	Mtx operator * (Mtx b){
		Mtx c(row,b.col); 
		for(int i=1;i<=c.row;i++){
			for(int j=1;j<=c.col;j++){
				for(int k=1;k<=col;k++){
					c.m[i][j] = min({c.m[i][j],m[i][k] + b.m[k][j]});
				}
			}
		}
		return c;
	}
	void print(){
		cout<<"_______________________\n";
		for(int i=1;i<=row;i++){
			for(int j=1;j<=col;j++){
				cout<<(m[i][j] > 1e17 ? -1 : m[i][j])<<" \n"[j==col];
			}
			cout<<'\n';
		}
		cout<<"_______________________\n";
	}
};
Mtx I(int r){
	Mtx res(r,r);
	for(int i=1;i<=r;i++){
		res.m[i][i] = 0;	
	}
	return res;
}
Mtx qmi(Mtx a,int b){
	Mtx res = I(a.row);
	while(b){
		if(b & 1) res = res * a;
		b >>= 1;
		a = a * a;
	}
	return res;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int n,m,k;
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i != j){
				d[i][j] = 1e18;
			}
		}
	}
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		e.push_back({u,v,w});
		d[u][v] = w;
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				d[i][j] = min(d[i][j],d[i][k] + d[k][j]);
			}
		}
	}
	Mtx a = I(n);
	for(int i=0;i<e.size();i++){
		int u = e[i].u,v = e[i].v,w = e[i].w;
		for(int j=1;j<=n;j++){
			for(int k=1;k<=n;k++){
				a.m[j][k] = min(a.m[j][k],d[j][u] + d[v][k] - w);
			}
		}
	}
	if(k){
		a = qmi(a,k);
		cout<<a.m[1][n];
	}else{
		cout<<d[1][n];
	}
	return 0;
}
posted @ 2026-07-03 07:46  yutar  阅读(5)  评论(0)    收藏  举报