codeforces 715 B Complete The Graph(二分+最短路)

本文介绍了一种算法,旨在解决给定无向图中,通过补全未知边长使从起点到终点的最短路径等于指定长度的问题。算法分为三步:初步判断、设置未知边为1进行最短路径计算、最后通过二分查找确定未知边的确切长度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题解:

题意大致为给定1e31e31e3的无向图,且给定起点sss和终点ttt,以及部分知道长度的边,让你补全不知道长度的边使得从sssttt的最短路为LLL

解题可以分为3个步骤

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

代码:

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
//#include <random>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define PB push_back
#define MP make_pair
#define INF 1073741824
#define inf 1000000000000000000
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
//mt19937 rand_(time(0));
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//逆元
ll wei[M];
int head[N],NEXT[M],ver[M],tot;void link(int u,int v,ll w){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;wei[tot]=w;}
ll dis[N];
bool vis[N],mark[N],flag[N];
int que[N],pre[N];
int s,t;
int n;
ll L;
bool dij(int x){
    for(int i=1;i<=n;i++){
        dis[i]=inf;
        vis[i]=false;
    }
    dis[x]=0;
    priority_queue<pair<ll,int> >q;
    q.push(MP(0,x));
    while(!q.empty()){
        x=q.top().second;
        q.pop();
        if(vis[x]) continue;
        vis[x]=true;
        for(int i=head[x];i;i=NEXT[i]){
            int y=ver[i];
            if(mark[i/2]) continue;
            if(dis[y]>dis[x]+wei[i]){
                dis[y]=dis[x]+wei[i];
                q.push(MP(-dis[y],y));
            }
        }
    }
    if(dis[t]<L) return false;
    else true;
}
bool DIJ(int x){
    for(int i=1;i<=n;i++){
        dis[i]=inf;
        vis[i]=false;
    }
    dis[x]=0;
    priority_queue<pair<ll,int> >q;
    q.push(MP(0,x));
    while(!q.empty()){
        x=q.top().second;
        q.pop();
        if(vis[x]) continue;
        vis[x]=true;
        for(int i=head[x];i;i=NEXT[i]){
            int y=ver[i];
            //cout<<mark[i/2]<<' '<<y<<' '<<x<<endl;
            if(dis[y]>dis[x]+(mark[i/2]?1LL:wei[i])){
                dis[y]=dis[x]+(mark[i/2]?1LL:wei[i]);
                q.push(MP(-dis[y],y));
                pre[y]=i;
                //cout<<y<<' '<<x<<endl;
            }
        }
    }
//    for(int i=1;i<=n;i++) cout<<dis[i]<<' ';
//    cout<<endl;
    //cout<<dis[t]<<endl;
    if(dis[t]>L) return false;
    else true;
}
void dijs(int x){
    for(int i=1;i<=n;i++){
        dis[i]=inf;
        vis[i]=false;
    }
    dis[x]=0;
    priority_queue<pair<ll,int> >q;
    q.push(MP(0,x));
    while(!q.empty()){
        x=q.top().second;
        q.pop();
        if(vis[x]) continue;
        vis[x]=true;
        for(int i=head[x];i;i=NEXT[i]){
            int y=ver[i];
            if(dis[y]>dis[x]+wei[i]){
                dis[y]=dis[x]+wei[i];
                q.push(MP(-dis[y],y));
            }
        }
    }
}
int main(){
    //freopen("1.txt","r",stdin);
    //ios::sync_with_stdio(false);
    int m;
    int u,v;
    ll w;
    tot=1;
    scanf("%d%d%d%d%d",&n,&m,&L,&s,&t);
    s++,t++;
    for(int i=1;i<=m;i++){
        scanf("%d%d%lld",&u,&v,&w);
        link(u+1,v+1,w);
        link(v+1,u+1,w);
        if(w==0) mark[i]=true;
    }
    if(dij(s)){
        if(dis[t]==L){
            puts("YES");
            for(int i=1;i<=m;i++){
                if(mark[i])
                    printf("%d %d %lld\n",ver[i*2+1]-1,ver[i*2]-1,inf);
                else
                    printf("%d %d %lld\n",ver[i*2+1]-1,ver[i*2]-1,wei[i*2]);
            }
            return 0;
        }
        if(DIJ(s)){
            int tmp=t;
            int ant=0;
            while(tmp!=s){
                if(mark[pre[tmp]/2]){
                    que[++ant]=pre[tmp]/2;
                    flag[pre[tmp]/2]=true;
                }
                tmp=ver[pre[tmp]^1];
            }
            for(int i=1;i<=m;i++){
                if(mark[i]){
                    if(flag[i]){
                        wei[i*2]=wei[i*2+1]=1LL;
                    }
                    else {
                        wei[i*2]=wei[i*2+1]=inf;
                    }
                }
            }
            for(int i=1;i<=ant;i++){
            ll l=1,r=inf;
            while(l<=r){
                ll mi=(l+r)/2LL;
                wei[que[i]*2]=wei[que[i]*2+1]=mi;
                dijs(s);
                if(dis[t]>L) r=mi-1;
                else l=mi+1;
            }
            wei[que[i]*2]=wei[que[i]*2+1]=r;
            dijs(s);
            if(dis[t]==L) break;
            }
            puts("YES");
            for(int i=1;i<=m;i++){
                if(mark[i])
                    printf("%d %d %lld\n",ver[i*2+1]-1,ver[i*2]-1,wei[i*2]);
                else
                    printf("%d %d %lld\n",ver[i*2+1]-1,ver[i*2]-1,wei[i*2]);
            }
        }
        else puts("NO");
    }
    else puts("NO");
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}
To find the shortest path from a given starting node s to any other nodes in the (undirected) graph, we can use Breadth-First Search (BFS) algorithm. The basic idea of BFS is to explore all the vertices at distance 1 from the current vertex before moving on to vertices at distance 2. Here is the implementation of the shortest_path function using BFS algorithm: ``` from collections import deque def shortest_path(adj_list, s): n = len(adj_list) visited = [False] * n distance = [float('inf')] * n distance[s] = 0 queue = deque([s]) while queue: u = queue.popleft() visited[u] = True for v in adj_list[u]: if not visited[v]: visited[v] = True distance[v] = distance[u] + 1 queue.append(v) for i in range(n): if not visited[i]: distance[i] = float('inf') return distance ``` In the above code, we first initialize two lists: visited and distance. The visited list is used to keep track of the visited nodes and the distance list is used to store the shortest distance from the starting node to all other nodes. We initialize all the distances as infinity except the distance of the starting node which is set to 0. We then use a deque (double-ended queue) to implement the BFS algorithm. We start by adding the starting node to the queue. Then, while the queue is not empty, we remove a vertex u from the front of the queue and mark it as visited. We then iterate over all the neighbors v of u and if v is not visited, we mark it as visited, update its distance from the starting node and add it to the end of the queue. Finally, we check if there are any nodes that were not visited during the BFS traversal and set their distance as infinity. We then return the distance list. Let's use the above code to solve the given example: ``` adj_list = [[], [2, 3], [1, 4], [1], [2]] d = shortest_path(adj_list, 0) print(d) # Output: [0, inf, inf, inf, inf] d = shortest_path(adj_list, 2) print(d) # Output: [inf, 1, 0, 2, 1] ``` In the first test case, the starting node is 0 and there are no edges connected to it. Hence, the distance to all other nodes is infinity. In the second test case, the starting node is 2 and the shortest path to node 2 is 0 (itself). The shortest path to node 1 is 1 (through node 2), the shortest path to node 3 is 2 (through nodes 2 and 1), and the shortest path to node 4 is 1 (through node 2).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值