Loading

CF715B Complete The Graph

题面

调出一堆 \(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\n", e[i].u, e[i].v, e[i].w);
   }
   return 0; 
}
posted @ 2021-07-22 16:35  Dita  阅读(45)  评论(0编辑  收藏  举报