CF_576D_Flights for Regular Customers_矩阵乘法+倍增floyd+bitset
https://www.luogu.org/problemnew/show/CF576D
按d排序,然后对于两个相邻的d,设map[i][j][k]表示从i到j走k步能否走到。
走di-di-1步可以用矩乘优化一下。
对于1和n连通的所有情况,跑一遍bfs,取min即可获得答案。
需要加bitset。
代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <bitset> using namespace std; int vis[160],Q[160],l,r,dis[160]; int n,m,a[160][160]; struct Mat { bitset<151>v[151]; Mat operator * (const Mat &x) const { Mat re;int i,j; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { if(v[i][j]) re.v[i]|=x.v[j]; } } return re; } }MAP,RE; void Qp(int y) { int i,j; for(i=1;i<=n;i++) for(j=1;j<=n;j++) MAP.v[i][j]=a[i][j]; for(;y;y>>=1,MAP=MAP*MAP) { if(y&1) RE=RE*MAP; } } struct A { int x,y,z; bool operator < (const A &u) const { return z<u.z; } }e[160]; bool bfs() { l=r=0; memset(dis,0,sizeof(dis)); memset(vis,0,sizeof(vis)); int i; for(i=1;i<=n;i++) if(RE.v[1][i]) Q[r++]=i,vis[i]=1; while(l<r) { int x=Q[l++]; for(i=1;i<=n;i++) { if(a[x][i]&&!vis[i]) { vis[i]=1; Q[r++]=i; dis[i]=dis[x]+1; } } } return vis[n]; } int main() { scanf("%d%d",&n,&m); int i,j=0; for(i=1;i<=m;i++) { scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z); } sort(e+1,e+m+1); int lst=0,ans=1<<30; RE.v[1][1]=1; while(1) { // puts("FUCK"); for(i=j+1;i<=m;i++) { if(e[i].z>lst) break; a[e[i].x][e[i].y]=1; j++; } if(bfs()) ans=min(ans,lst+dis[n]); if(j==m) break; Qp(e[j+1].z-lst); lst=e[j+1].z; } // for(i=1;i<=n;i++) {for(j=1;j<=n;j++) printf("%d ",RE.v[i][j]==1);puts("");} if(ans==1<<30) puts("Impossible"); else printf("%d ",ans); } /* 3 2 1 2 0 2 3 1 3 3 2 1 0 2 3 6 1 2 0 */