【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\times n$的矩阵,我们构造加入前i+1条边的图的邻接矩阵$A$(矩阵显然是$n\times n$的)

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

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

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

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

然后就没有了

时间复杂度:$O(n^3\log 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\n"); 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\n");
53     else printf("%d\n",ans);
54 }

 

posted @ 2019-02-13 19:20  AlphaInf  阅读(137)  评论(0编辑  收藏  举报