• bzoj4386 Wycieczki


    题目描述

    给定一张n个点m条边的带权有向图,每条边的边权只可能是1,2,3中的一种。
    将所有可能的路径按路径长度排序,请输出第k小的路径的长度,注意路径不一定是简单路径,即可以重复走同一个点。

    输入

    第一行包含三个整数n,m,k(1<=n<=40,1<=m<=1000,1<=k<=10^18)。
    接下来m行,每行三个整数u,v,c(1<=u,v<=n,u不等于v,1<=c<=3),表示从u出发有一条到v的单向边,边长为c。
    可能有重边。

    输出

    包含一行一个正整数,即第k短的路径的长度,如果不存在,输出-1。

    样例输入

    6 6 11
    1 2 1
    2 3 2
    3 4 2
    4 5 1
    5 3 1
    4 6 3

    样例输出

    4


    solution

    考虑只有边权为1的图。

    拿一个矩阵G[i][j]表示i到j有多少走法。他的x次幂就是i走恰好x步到j的情况。

    那么小于等于x的怎么求呢。

    可以加一个计数点。把所有点向计数点连边,再加一个自环,也就是i-1步的方案也算进i步的方案。

    现在考虑边权123

    把每个点新建2个虚点,分别为 i+n i+n+n

    如果i~j有x的边

    连i+(x-1)*n~j

    注意爆ll

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define ll unsigned long long
    using namespace std;
    int N,n,m;
    ll goal;
    ll Ans;
    struct node{
        ll v[125][125];
        void cle(){
            for(int i=1;i<=N;i++)
        for(int j=1;j<=N;j++)v[i][j]=0;
        }
    }G,A[70],ans,tmp;
    node operator *(node A,node B){
        node C;C.cle();
        for(int i=1;i<=N;i++)
        for(int j=1;j<=N;j++){
            for(int k=1;k<=N;k++){
                C.v[i][j]+=A.v[i][k]*B.v[k][j];
                if(C.v[i][j]>1e19){C.v[0][0]=-1;return C;}
            }
        }
        return C;
    }
    bool pd(){
        if(tmp.v[0][0]<0){return 0;}
        ll sum=0;
        for(int i=1;i<=n;i++){
            sum+=(tmp.v[i][N]-1);
            if(sum>1e19)return 0;
            //cout<<tmp.v[i][N]<<' ';
        }
        //cout<<"sum "<<sum<<endl;
        return sum<goal;
    }
    int main(){
        cin>>n>>m>>goal;N=n+n+n+1;//goal+=n;
        for(int i=1;i<=n;i++){
            G.v[i][i+n]=G.v[i+n][i+n+n]=1;
            G.v[i][N]=1;
        }
        G.v[N][N]=1;
        for(int i=1,t1,t2,t3;i<=m;i++){
            scanf("%d%d%d",&t1,&t2,&t3);
            G.v[t1+(t3-1)*n][t2]++;
        }
        A[0]=G;
    
        for(int i=1;i<=63;i++)A[i]=A[i-1]*A[i-1];
        for(int i=1;i<=n;i++)ans.v[i][i]=1;
        for(int i=63;i>=0;i--){
            tmp=ans*A[i];
            if(pd())ans=tmp,Ans += (1ll << i);
            if(i==63&&pd()){puts("-1");return 0;}
        }
        cout<<Ans<<endl;
        return 0;
    }
    /*
    2 1 1
    1 2 1
    
    */
    View Code

     

  • 相关阅读:
    Java实现 LeetCode 657 机器人能否返回原点(暴力大法)
    PHP imagearc
    PHP imageantialias
    PHP imagealphablending
    PHP imageaffinematrixget
    PHP imageaffinematrixconcat
    空单元 | empty-cells (Miscellaneous Level 2)
    矩阵 | matrix() (Transforms)
    相邻兄弟选择器 | Adjacent sibling selectors (Selectors)
    相抵路径 | offset-path (Motion Path)
  • 原文地址:https://www.cnblogs.com/liankewei/p/10403417.html
Copyright © 2020-2023  润新知