【xsy2748】 fly 矩阵快速幂

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

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

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

数据范围:n,m100,max(ti)109

 

此题貌似是一个套路题

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

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

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

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

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

单次矩乘的复杂度是O(n2),加入矩阵快速幂转移就是O(n2log(ti+1ti))

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

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

然后就没有了

时间复杂度:O(n3logT)

 

复制代码
 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 @   AlphaInf  阅读(139)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示