题解:P5590 赛车游戏

这个题,怎么这么牛。

思路

考虑所有 \(1 \to n\) 的长度等长的限制,这个条件等价于,每条边都可以作为最短路上的边。对于传统的差分约束,我们有 \(d_u \le d_v+w\),显然,当 \((u,v)\) 被最短路经过时,有 \(d_u=d_v+w\),因为如果 \(d_u\)\(d_v +w\) 小, \(d_u\) 就会被松弛,这样就满足了所有最短路相等的限制,洛谷上很多题解这个点都是没讲清楚的。对于此题,我们有 \(w \in [1,9]\),把前面的等式移项,得到 \(d_u-d_v=w\),即 \(1 \le d_u-d_v \le 9\),跑差分约束即可。

然后需要注意,跑差分约束的时候只需要保留 \(1 \to u\)\(u \to n\)\(u\),其余随便赋一个值即可,具体实现可以正图反图分别跑一遍 DFS。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1005,M=2005;
struct edge{
    int to,nxt;
}e[2][M*2];
int hd[2][N],tot1,tot2;
int uu[M],vv[M],ww[M]; 
void add(int u,int v,int op){
    if(op==0){
        e[0][++tot1].to=v;
        e[0][tot1].nxt=hd[0][u];
        hd[0][u]=tot1;
    }else{
        e[1][++tot2].to=v;
        e[1][tot2].nxt=hd[1][u];
        hd[1][u]=tot2;
    }
}
int tag[2][N],op;
void dfs(int u){
    tag[op][u]=1;
    for (int i=hd[op][u];i;i=e[op][i].nxt){
        int v=e[op][i].to;
        if (tag[op][v])continue;
        dfs(v);
    }
}
struct edge2{
    int to,nxt,w;
}Ee[M*4];
int H[N],tt,dis[N],cnt[N];
bool vis[N];
void Add(int u,int v,int w){
    Ee[++tt]={v,H[u],w};
    H[u]=tt;
}
bool spfa(int s,int n){
    memset(dis,0x3f,sizeof dis);
    memset(cnt,0,sizeof cnt);
    memset(vis,0,sizeof vis);
    queue<int>q;
    dis[s]=0;
    vis[s]=1;
    q.push(s);
    while(!q.empty()){
        int u=q.front();q.pop();
        vis[u]=0;
        for(int i=H[u];i;i=Ee[i].nxt){
            int y=Ee[i].to;
            if(dis[y]>dis[u]+Ee[i].w){
                dis[y]=dis[u]+Ee[i].w;
                if(!vis[y]){
                    if(++cnt[y]>n)return 1;
                    vis[y]=1;
                    q.push(y);
                }
            }
        }
    }
    return 0;
}
int main(){
    int n,m;cin>>n>>m;
    for (int i=1;i<=m;++i){
        int u,v;cin>>u>>v;
        uu[i]=u;vv[i]=v;
        add(u,v,0);
        add(v,u,1);
    }
    op=0; dfs(1);
    op=1; dfs(n);
    if(!tag[0][n]){
        cout<<-1;
        return 0;
    }
    memset(H,0,sizeof H);
    tt=0;
    for(int i=1;i<=m;++i){
        int u=uu[i],v=vv[i];
        if(tag[0][u]&&tag[1][u]&&tag[0][v]&&tag[1][v]){
            Add(v,u,-1);
            Add(u,v,9);
        }else{
            ww[i]=1;
        }
    }
    for(int i=1;i<=n;++i){
        Add(0,i,0);
    }
    if(spfa(0,n+1)){
        cout<<-1;
        return 0;
    }
    for(int i=1;i<=m;++i){
        int u=uu[i],v=vv[i];
        if(tag[0][u]&&tag[1][u]&&tag[0][v]&&tag[1][v]){
            int w=dis[v]-dis[u];
            if(w<1||w>9){
                cout<<-1;
                return 0;
            }
            ww[i]=w;
        }else{
            ww[i]=1;
        }
    }
    cout<<n<<" "<<m<<"\n";
    for(int i=1;i<=m;++i){
        cout<<uu[i]<<" "<<vv[i]<<" "<<ww[i]<<"\n";
    }
    return 0;
}
posted @ 2026-02-27 11:47  Cefgskol  阅读(8)  评论(0)    收藏  举报