1. 程式人生 > 實用技巧 >[ cf1407D ] 最短路+思維

[ cf1407D ] 最短路+思維

E. Egor in the Republic of Dagestan

題意:n個點,m條邊的有向圖。從1號點出發到n號點。每個邊有黑白兩色,你需要對點染色,一點可以通過同色邊到達另一點,求如何對所有點染色,使1到n的最短距離最大,或者根本不能到達?

題解:從n開始倒著bfs即可。如果第一次遇到某個點,則說明在真的最短路上,為了避免走這條路,我們將該點染成和連邊相反的顏色即可。如果之後又遇到這個點則根據顏色來決定是否鬆弛,並加入佇列。

#include<bits/stdc++.h>
#define ll long long
#define pll pair<ll,ll>
#define pii pair<int,int>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define mem0(x) memset(x,0,sizeof(x))
#define meminf(x) memset(x,0x3f,sizeof(x))
#define VI vector<int>
#define VL vector<ll>
using namespace  std;

const int N = 5e5+5;
int color[N], dis[N],vis[N];
vector<vector<pii>> g(N); 
queue<int> q;
int main(){
    ios::sync_with_stdio(0);
    int n,m;cin>>n>>m;
    rep(i,1,m){
        int u,v,t;
        cin>>u>>v>>t;
        g[v].push_back({u,t}); 
    }
    meminf(dis);memset(color,-1,sizeof(color));
    color[n] = dis[n] = 0;
    
    q.push(n);
    while(!q.empty()){
        int v= q.front();q.pop();
        vis[v] = 1;
        for(auto&it :g[v]){
            int u = it.first,t = it.second;
            if(vis[u]) continue;
            if(color[u]==-1){
                color[u] = 1-t;
            }else{
                if(color[u]==t&&dis[u]>dis[v]+1){
                    dis[u] = dis[v]+1;
                    q.push(u);
                }
            }
        }
    }

    int ans;
    if(dis[1] == 0x3f3f3f3f){
        ans = -1;
    }else{
        ans = dis[1];
    }
    cout<<ans<<endl;
    rep(i,1,n){
        cout<<max(0,color[i]);
    }
    cout<<endl;
    
}