• 周一. 8月 15th, 2022

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

CF715B Complete The Graph

admin

11月 28, 2021

题面

调出一堆 (sb)​​ 错误的题,例如:”YES” 写成“Yes”将近半下午没了 = =

给你一张 (n) 个点,(m) 条边的图,每条边有一个正整数权值。有些边的边权未知。你需要给每条权值未知的边确定一个不超过 (10^{18}) 的正整数权值,使得 (S)(T) 的最短路恰好为 (L)

无解输出 (−1)

(2 ≤ n ≤ 1000,1 ≤ m ≤ 2000,1 ≤ L ≤ 10^9,S ≠ T)

solution

首先把未知的边的权值都赋为最小的正整数 (1), 然后跑一遍最短路,如果最短路的长度大于 (L) 那么最短路肯定不会是 (L)

如果最短路的恰好等于 (L) 直接输出答案就好了

对于如果大于 (L)

一开始是这么想的:跑一遍最短路,然后找出最短路上的可以变化权值的边(一开始为 0 的边)增大权值,直到这条最短路恰好为 L,然后继续跑最短路,判断是否还存在 < L 的最短路,重复这个操作,直到找不到为止,这样到最后肯定存在一条长度为 (L) 的最短路

发现这样会跑很多次最短路,就没写 (其实是我不会写)

题解的思路

跑两次最短路,第一次的记为 (dis[i][0]) 第二次的记为 (dis[i][1])

先跑完第一次最短路,求出 (need = L – dis[T][0]) 也就是距目标还差多少

跑第二次最短路的时候,如果到达一个点的最短路可以更新,并且 (dis[u] + e[i].w < dis[v] + need) 就把 (e[i].w) 更新为 (dis[v] + need – dis[u])

这样走到 (v) 点就相当于最短路加上了 (need) 妙哉 = =

code

/*
work by:Ariel_
mind: 把未知的边都设为 1,跑一遍最短路,如果最短路大于 L,则一定无解
如果此时 = L, 此时就是答案
如果此时小于 L,就调整这条路径上的边,使得它成为 L,然后再跑最短路,重复此操作
直到最后找不到小于 L 的路径
判断一条边是否为最短路上的边:两边 dij, 
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#define int long long
#define rg register
using namespace std;
const int M = 1e5 + 5, N = 1e5 + 5;
const int INF = 0x3f3f3f3f3f3f;
typedef pair<int, int> PII;
int read(){
    int x = 0,f = 1; char c = getchar();
    while(c < '0'||c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = x*10 + c - '0'; c = getchar();}
    return x*f;
}
int n, m, L, S, T, opt[N], need;
struct edge{int u, v, nxt, w, fag;}e[M];
int head[N], E = 1;
void add_edge(int u, int v, int w, int fag) {
   e[++E] = (edge) {u, v, head[u], w + fag, fag};
   head[u] = E;
}
priority_queue<PII, vector<PII>, greater<PII> > q;
int dis[N][2], vis[N];
void dij(int k) {
   memset(vis, 0, sizeof vis);
   for (int i = 0; i < n; i++) dis[i][k] = INF;
   dis[S][k] = 0, q.push(make_pair(0, S));
   while(!q.empty()) {
   	  int u = q.top().second; q.pop(); 
	  if (vis[u]) continue;
	  vis[u] = 1;
   	  for (int i = head[u]; i; i = e[i].nxt) {
   	  	    int v = e[i].v;
   	  	    if (k == 1) {
   	  	       if (k && e[i].fag && dis[u][1] + e[i].w < dis[v][0] + need)
   	  	       	 e[i].w = e[i ^ 1].w = dis[v][0] + need - dis[u][1];
			}
   	  	    if (dis[v][k] > dis[u][k] + e[i].w) {
   	  	        dis[v][k] = dis[u][k] + e[i].w;
			    q.push(make_pair(dis[v][k], v));	
			 }   
		}
   }
}
signed main(){
   n = read(), m = read(), L = read(), S = read(), T = read();
   for (int i = 1, u, v, w; i <= m; i++) {
   	 u = read(), v = read(), w = read();
   	 add_edge(u, v, w, !w), add_edge(v, u, w, !w);	
   }
   dij(0);
   if (dis[T][0] > L) {
   	  puts("NO"); return 0;
   }
   need = L - dis[T][0];
   dij(1);
   if (dis[T][1] != L) puts("NO");
   else {
   	  puts("YES");
   	  for (int i = 2; i <= E; i += 2)  printf("%lld %lld %lld
", e[i].u, e[i].v, e[i].w);
   }
   return 0; 
}

发表回复

您的电子邮箱地址不会被公开。