• 【xsy2748】 fly 矩阵快速幂


    题目大意:有$n$个点,$m$条有向边,其中第$i$条边需要在$t_i$秒后才出现在图上。

    有一个人刚开始呆在$1$号节点,每秒钟他必须要选择一条从他所在位置走出去的边,走出去(如果没有的话这人就死了)

    问你他从$1$号点走到$n$号所需的最少时间。

    数据范围:$n,m≤100,max(t_i)≤10^9$

    此题貌似是一个套路题

    令$vis[T][i]$表示在时刻$T$,是否能够到达$i$号节点

    我们可以用$O(m)$的时间基于$vis[T][i]$求出$vis[T+1][i]$。

    然而这么搞复杂度直接爆炸了。

    我们把$vis[T]$看做是一个$1 imes n$的矩阵,我们构造加入前i+1条边的图的邻接矩阵$A$(矩阵显然是$n imes n$的)

    不难发现$vis[T+1]=vis[T] imes A$,这里的乘法是矩阵乘法。

    单次矩乘的复杂度是$O(n^2)$,加入矩阵快速幂转移就是$O(n^2log(t_{i+1}-t_i))$。

    然而这么求我们只会求出$vis$数组的某一些项,然而某条边被加入后是一直存在的。

    不难发现我们只需要在时刻$t_{i+1}$的基础上再走上$n$步,就可以知道是否可以在加入这条边后到达终点(结论显然)

    然后就没有了

    时间复杂度:$O(n^3log T)$

     1 #include<bits/stdc++.h>
     2 #define M 105
     3 #define INF 1234567890
     4 using namespace std;
     5 
     6 struct mat{
     7     bool a[M][M]; int n,m;
     8     mat(){memset(a,0,sizeof(a));}
     9     mat(int nn,int mm){memset(a,0,sizeof(a)); n=nn; m=mm;}
    10     void set1(){memset(a,0,sizeof(a)); for(int i=1;i<=n;i++) a[i][i]=1;}
    11     friend mat operator *(mat a,mat b){
    12         mat c=mat(a.n,b.m);
    13         for(int i=1;i<=a.n;i++)
    14         for(int k=1;k<=b.n;k++) if(a.a[i][k])
    15         for(int j=1;j<=a.m;j++)
    16         c.a[i][j]|=a.a[i][k]&b.a[k][j];
    17         return c;
    18     }
    19     friend mat operator ^(mat a,int b){
    20         mat ans=mat(a.n,a.m); ans.set1();
    21         while(b){
    22             if(b&1) ans=ans*a;
    23             b=b>>1; a=a*a;
    24         }
    25         return ans;
    26     }
    27 }a,b;
    28 struct edge{
    29     int u,v,t;
    30     void rd(){scanf("%d%d%d",&u,&v,&t);}
    31     friend bool operator <(edge a,edge b){return a.t<b.t;}
    32 }p[M];
    33 int n,m,ans=INF;
    34 int main(){
    35     scanf("%d%d",&n,&m);
    36     a=mat(1,n); b=mat(n,n); a.a[1][1]=1;
    37     if(n==1) {printf("0
    "); return 0;}
    38     for(int i=1;i<=m;i++) p[i].rd();
    39     sort(p+1,p+m+1);
    40     for(int i=1;i<=m;i++){
    41         mat hh=a;
    42         b.a[p[i].u][p[i].v]=1;
    43         for(int j=1;j<=n;j++){
    44             hh=hh*b;
    45             if(hh.a[1][n]){
    46                 ans=min(ans,p[i].t+j);
    47                 break;
    48             }
    49         }
    50         if(i<m) a=a*(b^(p[i+1].t-p[i].t));
    51     }
    52     if(ans==INF) printf("Impossible
    ");
    53     else printf("%d
    ",ans);
    54 }
  • 相关阅读:
    [转]如何避免外发邮件被误判为垃圾邮件
    [转]php判断一个数组是另一个数组的子集
    [转]Linux下Nagios的安装与配置
    [转]MySQL事务学习-->隔离级别
    [转]最完美解决Nginx部署ThinkPHP项目的办法
    [转]Redis作者:深度剖析Redis持久化
    Html、Asp、Php、Jsp禁止页面缓存
    JS模板引擎
    HTTPS安全证书介绍
    PHP Curl实例
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10371519.html
Copyright © 2020-2023  润新知