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的最佳代码片段网站是啥[重复]

OJ1751最佳南瓜

ZSTU OJ 4272 最佳淘汰算法

RTD2171芯片停产替代型号CS5261|CS5261完美替代RTD2171芯片

九度oj 题目1397:查找数段

2171 棋盘覆盖