标签:using 转化 ace 需要 strong while names \n 矩阵乘法
题目大意 : 给出一个 \(n\) 个顶点 \(m\) 条边的带权有向图,你要从 \(1\) 号点到 \(n\) 号点,途中你可以进行不超过 \(C\) 次操作:经过一条边时,将这条边的边权取反一次,经过后该边权复原。求 \(1\) 号点到 \(n\) 号点的最短路径。(保证一开始边权为非负,不保证最后答案非负。) \((n≤100,m≤20000,C≤300000)\)
Tag: 最短路、矩阵快速幂
Analysis By LC:
我们先求出不操作和操作一次的最短路径图:我们将原图复制一份,若两点之间有边,则在两图的两点间连一条边权取反的边,即若 \(u\rightarrow v\) 边权为 \(w\) ,则 \(u_1 \rightarrow v_1\) 边权为 \(w\) , \(u\rightarrow v_1\) 边权为 \(-w\) ,这样跑一遍最短路即可求出不操作和操作一次的最短路。(详解:你操作一次后,相当于从原图走了一条路径到了复制图,那么原图的点到复制图的点的最短路即为操作一次的最短路。)
那么得到了操作一次的最短路就可以得到操作 \(C\) 次的最短路:因为在操作一次的图上,每经过一个点就相当于进行了一次操作,那么我们的问题就可以转化为:求经过不超过 \(C\) 个点的最短路,这是一类经典的图邻接矩阵快速幂的问题,可以直接用矩阵快速幂求解。需要注意的是 \(C\) 为 \(0\) 的情况,你可以快速幂后再乘上不操作的图,也可以直接特判输出不操作的最短路径。
这是一个很有意思的题目(lzz大佬的题),欢迎大家来玩!
Code By LC :
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=105;
int n,m,c,ma[N*2][N*2];
inline int _read()
{
char c; int x=0;
for(;c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
return x;
}
struct matrix
{
ll a[N][N];
matrix() {
memset(a,0x3f,sizeof(a));
for(int i=1;i<=n;i++)
a[i][i]=0;
};
matrix operator * (matrix s) const { //矩阵乘法改为松弛操作
matrix ret;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
ret.a[i][j]=min(ret.a[i][j],a[i][k]+s.a[k][j]);
return ret;
}
};
matrix mpow(matrix s, int t) //矩阵快速幂
{
matrix ret;
while(t)
{
if(t&1) ret=ret*s;
s=s*s; t>>=1;
}
return ret;
}
void floyd() //求不操作和操作一次的最短路
{
for(int k=1;k<=n*2;k++)
for(int i=1;i<=n*2;i++)
for(int j=1;j<=n*2;j++)
ma[i][j]=min(ma[i][j],ma[i][k]+ma[k][j]);
}
int main()
{
int T=_read();
while(T--)
{
n=_read(),m=_read(),c=_read();
memset(ma,0x3f,sizeof(ma));
for(int i=1;i<=n;i++) ma[i][i]=ma[i][i+n]=0;
while(m--)
{
int u=_read(),v=_read(),w=_read();
ma[u][v]=ma[u+n][v+n]=min(w,ma[u][v]); //原图复制一份,重新构图
ma[u][v+n]=min(-w,ma[u][v+n]); //两图间连边权为负的边
}
floyd();
matrix x,y;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
x.a[i][j]=ma[i][j],y.a[i][j]=ma[i][j+n]; //x:不操作的最短路矩阵;y:操作一次……
matrix p=mpow(y,c);
x=x*p; //防止C=0,再乘上原矩阵
printf("%lld\n",x.a[1][n]);
}
}
标签:using 转化 ace 需要 strong while names \n 矩阵乘法
原文地址:https://www.cnblogs.com/farway17/p/9404506.html