OJ2171最佳路径
Posted farway17
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OJ2171最佳路径相关的知识,希望对你有一定的参考价值。
2171 -- 最佳路径(Solution)
题目大意 : 给出一个 (n) 个顶点 (m) 条边的带权有向图,你要从 (1) 号点到 (n) 号点,途中你可以进行不超过 (C) 次操作:经过一条边时,将这条边的边权取反一次,经过后该边权复原。求 (1) 号点到 (n) 号点的最短路径。(保证一开始边权为非负,不保证最后答案非负。) ((n≤100,m≤20000,C≤300000))
Tag: 最短路、矩阵快速幂
Analysis By LC:
我们先求出不操作和操作一次的最短路径图:我们将原图复制一份,若两点之间有边,则在两图的两点间连一条边权取反的边,即若 (u ightarrow v) 边权为 (w) ,则 (u_1 ightarrow v_1) 边权为 (w) , (u ightarrow 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
",x.a[1][n]);
}
}
以上是关于OJ2171最佳路径的主要内容,如果未能解决你的问题,请参考以下文章
iphone / Objective c的最佳代码片段网站是啥[重复]