题意

给出一张有向图,对于边\(i\)有限制条件\(d_i\),表示在走边\(i\)前必须走过至少\(d_i\)条其他的边。为从\(1\)\(n\)最少要走几条边。
无解输出\(Impossible\)

思路

特别棒的一篇
首先按照\(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\n",ans);
    else puts("Impossible");
    return 0;
}

后记

就是不停的挂,比如什么\(i,j\)或者\(n,N\)写反
还有\(ans\)的初始化不能太大也不能太小

01-25 12:27