题意
给出一张有向图,对于边(i)有限制条件(d_i),表示在走边(i)前必须走过至少(d_i)条其他的边。为从(1)到(n)最少要走几条边。
无解输出(Impossible)
(n leq 150,m leq 150,d_i leq 10^9)
思路
特别棒的一篇
首先按照(d)的大小升序排序
然后分成(m)个时刻处理,(can[i][j])表示当前时刻(i)能否走到(j)
更新(can)即通过上一次时刻乘上邻接矩阵的(d_i-d_{last})次方(注意邻接矩阵不断变化,每次处理完再加上一条边)
更新答案的时候,我们枚举每个点。
若(1)可以走到(i)点,则更新答案为(d_i(当前时刻走到i)+dis[i][n](从i还要走的路))。
最短路由(floyd)求解即可。考虑到d很大,用矩阵快速幂加速。
矩阵乘法的时候用(bitset)优化。
#include <bits/stdc++.h>
using namespace std;
const int N=160;
int ans=0x3f3f3f3f,n,m,dis[N][N],last;
bitset<N> can[N],a[N],t[N];
struct edge{
int x,y,d;
}e[N];
bool cmp(edge x,edge y){
return x.d<y.d;
}
void mul(bitset<N> *a,bitset<N> *b){
bitset<N> tt[N];
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (a[i][j]) tt[i]|=b[j];
for (int i=1;i<=n;i++) a[i]=tt[i];
}
void ksm(bitset<N> *a,int y){
bitset <N> Ans[N];
for (int i=1;i<=n;i++) Ans[i][i]=1;
for (;y;y>>=1,mul(a,a))
if (y&1) mul(Ans,a);
for (int i=1;i<=n;i++) a[i]=Ans[i];
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].d);
sort(e+1,e+m+1,cmp);
memset(dis,0x3f,sizeof(dis));
for (int i=1;i<=n;i++) dis[i][i]=0,can[i][i]=1;
for (int i=1;i<=m;i++){
int x=e[i].x,y=e[i].y,d=e[i].d;
for (int j=1;j<=n;j++) t[j]=a[j];
ksm(t,d-last);
mul(can,t);
for (int j=1;j<=n;j++)
for (int k=1;k<=n;k++)
dis[j][k]=min(dis[j][k],dis[j][x]+1+dis[y][k]);
for (int j=1;j<n;j++) if (can[1][j]) {
ans=min(ans,d+dis[j][n]);
}
last=d;
a[x][y]=1;
}
if (ans<0x3f3f3f3f) printf("%d
",ans);
else puts("Impossible");
return 0;
}
后记
就是不停的挂,比如什么(i,j)或者(n,N)写反
还有(ans)的初始化不能太大也不能太小