zoukankan      html  css  js  c++  java
  • [usaco2007 Nov]relays 奶牛接力跑 题解 重载矩阵乘法

    题目描述

    FJ的N(2 <= N <= 1,000,000)头奶牛选择了接力跑作为她们的日常锻炼项目。至于进行接力跑的地点 自然是在牧场中现有的T(2 <= T <= 100)条跑道上。 农场上的跑道有一些交汇点,每条跑道都连结了两个不同的交汇点 I1_i和I2_i(1 <= I1_i <= 1,000; 1 <= I2_i <= 1,000)。每个交汇点都是至少两条跑道的端点。 奶牛们知道每条跑道的长度length_i(1 <= length_i <= 1,000),以及每条跑道连结的交汇点的编号 并且,没有哪两个交汇点由两条不同的跑道直接相连。你可以认为这些交汇点和跑道构成了一张图。 为了完成一场接力跑,所有N头奶牛在跑步开始之前都要站在某个交汇点上(有些交汇点上可能站着不只1头奶牛)。当然,她们的站位要保证她们能够将接力棒顺次传递,并且最后持棒的奶牛要停在预设的终点。 你的任务是,写一个程序,计算在接力跑的起点(S)和终点(E)确定的情况下,奶牛们跑步路径可能的最小总长度。显然,这条路径必须恰好经过N条跑道。

    输入格式

    第1行: 4个用空格隔开的整数:N,T,S,以及E
    第2..T+1行: 第i+1为3个以空格隔开的整数:length_i,I1_i,以及I2_i, 描述了第i条跑道。

    输出格式

    第1行: 输出1个正整数,表示起点为S、终点为E,并且恰好经过N条跑道的路 径的最小长度

    样例

    样例输入

    2 6 6 4
    11 4 6
    4 4 8
    8 4 9
    6 6 8
    2 6 9
    3 8 9

    样例输出

    10

      思路:首先这个题的想法要和SCOI2009迷路的题类似,我并不倾向于把这题叫做倍增floyd,我认为这题从矩阵的角度更好理解,而且更能证明正确性,显然从迷路的思路我们得到这么几个条件,一个是矩阵存的路径数,一个是走几步。那么类比一下,我们当时要求k次的路径数,这时我们要求k条边的最短路,那么很容易我们想到了,矩阵里面存边权,代表i到j走一条边的最短路,那么我们可以yy一下,这个矩阵的k次幂就是i到j走k条边的最短路,那么显然之前矩阵的乘法是不能计算的,于是我们就想到了把矩阵乘法重载一下,变为c[i][j]=min(a[i][k]+a[k][j]),这也就是网上许多倍增floyd的由来,但是接下来要问了,floyd可以倍增么?换个问题就是这样做对吗?那么我们要从这种思路来看,我们没有证明我们重载过的矩阵运算满足交换律,即(a@a)@a==a@(a@a);那么这应该是这个算法的正确性,我们考虑实际含义,走2步再走1步,和走1步再走2步,最短路一定相同。当然并没有说倍增floyd错了,代码打出来都一样,以上均为个人见解。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=105,ID=1000,inf=0x7fffffff;
    int p[ID],m[N][N],l[N],n,k,s,e,cnt;
    struct mat
    {
        long long a[105][105],n;
        mat (int n,int x) :n(n)
        {
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                a[i][j]=x;
        }
        mat operator *(mat &b)
        {
            mat c(n,inf);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    for(int k=1;k<=n;k++)
                    c.a[i][j]=min(c.a[i][j],a[i][k]+b.a[k][j]);
            return c;
        }
        void print()
        {
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)
                if(a[i][j]==inf) printf("# ");
                else cout<<a[i][j]<<" ";
                cout<<endl;
            }
        }
    };
    int rd()
    {
        char cc=getchar();
        int s=0,w=1;
        while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
        while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
        return s*w;
    }
    mat qpow(mat a,int k)
    {
        mat ans=a;
        for(;k;k>>=1,a=a*a)if(k&1) ans=ans*a;
        return ans;
    }
    int main()
    {
        k=rd(),n=rd(),s=rd(),e=rd();
        for(int i=1,z,x,y;i<=n;i++)
        {
            z=rd(),x=rd(),y=rd();
            if(!p[x]) p[x]=++cnt;
            if(!p[y]) p[y]=++cnt;
            //printf("%d %d
    ",p[x],p[y]);
            m[p[x]][p[y]]=z;
            m[p[y]][p[x]]=z;
        }
        mat a(cnt,0);
        for(int i=1;i<=cnt;i++)
            for(int j=1;j<=cnt;j++)
                a.a[i][j]=m[i][j]?m[i][j]:inf;
        //a.print();
        mat c=qpow(a,k-1);
        //c.print();
        printf("%lld
    ",c.a[p[s]][p[e]]);
    }
    /*
    g++ 1.cpp -o 1
    ./1
    2 6 6 4
    11 4 6
    4 4 8
    8 4 9
    6 6 8
    2 6 9
    3 8 9
    */
    View Code
    Zeit und Raum trennen dich und mich.时空将你我分开。
  • 相关阅读:
    js中的原生Ajax和JQuery中的Ajax
    this的用法
    static的特性
    时政20180807
    java compiler没有1.8怎么办
    Description Resource Path Location Type Java compiler level does not match the version of the installed Java project facet Unknown Faceted Project Problem (Java Version Mismatch)
    分词器
    [数算]有一个工程甲、乙、丙单独做,分别要48天、72天、96天完成
    一点感想
    解析Excel文件 Apache POI框架使用
  • 原文地址:https://www.cnblogs.com/starsing/p/11204753.html
Copyright © 2011-2022 走看看