codeforces 715 B. Complete The Graph

 题目大意:有一个无向图,其中N个点,M条边,修改其中边权为0的所有边,使得他们的权值在1到1E18之间且从S到T的最短路的距离是L,请问是否存在修改方案,存在打出修改后所有边权的权值。

分析:如果直接暴力,显然1E18的复杂度会TLE,所以无脑二分,我们先判断如果边权为0的边,去掉后最短路的值,若这个值小于L显然是不存在的,若这个值等于L边权为0的边直接赋值1E18就行,之后将边权为0的边赋值为1,在跑一次最短路,因为经过了前两次的判断,那么,这个最短路肯定会经过原来0的边,赋值1后,逐条边进行调控就行,确保每次调控后的最短路小于等于L就行

具体步骤如下:

1.不将不知道长度的边跳过,求最短路,若最短路小于L则一定不可能成功输出NO,若等于则将未知边长设定为INF若大于则执行2
2.将所有未知边都设成1,跑最短路,若最短路大于L则一定不能成功(因为题意规定边长最小为1)输出NO,否则执行第3步
3.首先在第二步中回溯一遍最短路,将经过的未知边打上标记。对于未打上标记的未知边设值为INF,其他值为1,然后依次枚举这些点二分这些点的答案,跑最短路。(每次确定一点答案后再跑一遍最短路,若最短路为L则推出枚举)

//AC代码:

#include<vector>
#include<queue>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const ll maxn = 1100;
const ll N = 1e4 + 10;
const ll inf = 4e18 + 10;
const ll INF = 1e9 + 10;
struct edge{
    ll to;
    ll w;
}tex;
struct node{
    ll to;
    ll len;
    bool operator < (const node & fx) const{
        return  len > fx.len;
    }
}tey;
vector<struct edge>ver[maxn];
ll dis[maxn];
int vis[maxn];
int isin[maxn];
int isin2[maxn];
ll pre[maxn];
void dijkstra(ll s){
    priority_queue<struct node>q;
    fill(dis, dis + maxn, inf);
    memset(vis, 0, sizeof(vis));
    fill(pre, pre + maxn, -1);
    dis[s] = 0;
    tey.to = s;
    tey.len = 0;
    q.push(tey);
    while(!q.empty()){
        ll u = q.top().to;
        q.pop();
        if(vis[u] == 1)  continue;
        vis[u] = 1;
        for(int i = 0; i < ver[u].size(); i++){
            if(dis[u] + ver[u][i].w < dis[ver[u][i].to]){
                dis[ver[u][i].to] = dis[u] + ver[u][i].w;
                tey.to = ver[u][i].to;
                tey.len = dis[ver[u][i].to];
                q.push(tey);
                pre[ver[u][i].to] = u;
            }
        }
    }
    
}
vector<ll> xt, yt, stx, sty; 
vector<int>xz, yz, sxz, syz;
vector<ll>NG;
ll id[maxn][maxn];
int main(){
    memset(isin, 0, sizeof(isin));
    memset(isin2, 0, sizeof(isin2));
    ll n, m, s, t, bl;  ll u[N], v[N], w[N]; 
    cin>>n>>m>>bl>>s>>t;   int cnt = 0;
    for(ll i = 1; i <= m; i++){
        cin>>u[i]>>v[i]>>w[i];
        id[u[i]][v[i]] = id[v[i]][u[i]] = i;
        tex.to = v[i];  tex.w = w[i];
        ver[u[i]].push_back(tex);
        tex.to = u[i];
        ver[v[i]].push_back(tex);
        if(w[i] == 0){
           isin[u[i]] = 1;    isin[v[i]] = 1;
           xt.push_back(u[i]);
           yt.push_back(v[i]);
           xz.push_back(ver[u[i]].size() - 1);
           yz.push_back(ver[v[i]].size() - 1);
           NG.push_back(i);
           //cnt++;
        }
    }
    for(int i = 0; i < xt.size(); i++){
        ver[xt[i]][xz[i]].w = inf;
    }
    for(int i = 0; i < yt.size(); i++){
        ver[yt[i]][yz[i]].w = inf;
    }
    dijkstra(s);
    if(dis[t] < bl){
        cout<<"NO\n";
        return 0;
    }else if(dis[t] == bl){
        cout<<"YES\n";
        for(int i = 0; i < NG.size(); i++){
            w[NG[i]] = 1e18;    
        }
        for(ll i = 1; i <= m; i++){
            cout<<u[i]<<" "<<v[i]<<" "<<w[i]<<endl;
        }
        return 0;
    }
    for(int i = 0; i < xt.size(); i++){
        ver[xt[i]][xz[i]].w = 1;
    }
    for(int i = 0; i < yt.size(); i++){
        ver[yt[i]][yz[i]].w = 1;
    }
    dijkstra(s);
    if(dis[t] > bl){
        cout<<"NO\n";
        return 0;
    }else if(dis[t] == bl){
        cout<<"YES\n";
        for(int i = 0; i < NG.size(); i++){
            w[NG[i]] = 1; 
        }
        for(ll i = 1; i <= m; i++){
            cout<<u[i]<<" "<<v[i]<<" "<<w[i]<<endl;
        }
        return 0;
    }
    ll rt = t;
    while(rt != -1){
        if(pre[rt] != -1){
            if(isin[rt] && isin[pre[rt]]){
                isin2[rt] = 1;
                isin2[pre[rt]] = 1;
            }
        }
        rt = pre[rt];
    }
    for(int i = 0; i < xt.size(); i++){
        ll go = ver[xt[i]][xz[i]].to;
        if(isin2[go] && isin2[xt[i]]){
            ver[xt[i]][xz[i]].w = 1;
            w[id[xt[i]][go]] = 1;
            stx.push_back(xt[i]);
            sxz.push_back(xz[i]);
            cnt++;
        }else{
            ver[xt[i]][xz[i]].w = INF;
            w[id[xt[i]][go]] = INF;
        }  
    }
    for(int i = 0; i < yt.size(); i++){
        ll go = ver[yt[i]][yz[i]].to;
        if(isin2[go] && isin2[yt[i]]){
            ver[yt[i]][yz[i]].w = 1;
            w[id[yt[i]][go]] = 1;
            sty.push_back(yt[i]);
            syz.push_back(yz[i]);
        }else{
            ver[yt[i]][yz[i]].w = INF;
            w[id[yt[i]][go]] = INF;
        }  
    }
    //ll ans = -1;
    for(int i = 0; i < cnt; i++){
        ll l = 0;
        ll r = 1e18;
        while(l <= r){
               ll mid = (l + r)>>1;               
               ver[stx[i]][sxz[i]].w = mid;
              ver[sty[i]][syz[i]].w = mid;
               dijkstra(s);
               if(dis[t] > bl)   r = mid - 1;
               else    l = mid + 1;
        }
        ver[stx[i]][sxz[i]].w = r;
        ver[sty[i]][syz[i]].w = r;
        w[id[stx[i]][sty[i]]] = r;
        dijkstra(s);
        if(dis[t] == bl)  break;
    }
    cout<<"YES\n";
    for(ll i = 1; i <= m; i++){
        cout<<u[i]<<" "<<v[i]<<" "<<w[i]<<endl;
    }
    
    return 0;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值