Cow Relays POJ - 3613

这题面是外星人写的吧

定义一个群,其元素为一个矩阵,定义一个该群的元素M,并且M存着一个图。

定义一个二元运算符*,运算结果仍为该群的元素。

如M*M=R,则R(i,j)=Min(Rij,Mik+Mkj)

这个操作满足交换律和结合律。

其意义代表不言而喻。(手动滑稽)

因此可利用快速幂求解。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int MOD=1000;
const int sz=201;
int N,t,s,e,n;
struct mat{
    int a[sz][sz];
    mat(){memset(a,0,sizeof a);}
    void initE(){for(int i=0;i<n;i++)a[i][i]=1;}
    void initfib(){a[1][0]=a[0][1]=a[0][0]=1;a[1][1]=0;}
    mat operator*(const mat&t)const{
        mat q;memset(q.a,0x3f,sizeof q.a);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            for(int k=0;k<n;k++)
                q.a[i][j]=min(q.a[i][j],a[i][k]+t.a[k][j]);
        return q;
    }
    void out(){
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++)printf("%d ",a[i][j]);printf("\n");
        }
    }
    mat operator^(int k)const{
        mat res=*this;
        mat m=*this;
        //res.out();m.out();
        while(k>0){
            if(k&1)res=res*m;
            m=m*m;k>>=1;
        }
        return res;
    }

};
int mp[1010];
int main(){ 
    scanf("%d%d%d%d",&N,&t,&s,&e);
    n=0;
    for(int i=0;i<1010;i++)mp[i]=-1;
    mat m;memset(m.a,0x3f,sizeof m.a);
    while(t--){
        int l,x,y;
        scanf("%d%d%d",&l,&x,&y);
        int sx=mp[x],sy=mp[y];
        if(sx==-1)sx=mp[x]=n++;
        if(sy==-1)sy=mp[y]=n++;
        m.a[sx][sy]=m.a[sy][sx]=l;
    }
   // m.out();
    m=m^(N-1);
  //  m.out();
    printf("%d\n",m.a[mp[s]][mp[e]]);
    return 0;
}

 

posted @ 2017-10-09 11:23  MeowMeowMeow  阅读(182)  评论(0编辑  收藏  举报