Codeforces 715B - Complete The Graph
Published on 2016-09-18描述
给定一个 个点 的无向图,边权值 均为正整数,有一些边尚未被赋值,求一种边权的分配方案(只能分配正整数),使得 的最短路恰好为 。若不存在,输出 NO
。
分析
妈蛋这个题考试搞了很久都没做出来,想到了要去找 长度不超过 且有最少未赋值的边的路径,可是搞了一个小时,都没办法想出一个复杂度过得去的方案,我太弱了QAQ。
先判断无解,将所有未赋值的边给 ,如果 最短路长度还是 ,无解;将所有未赋值的边给 ,如果 最短路长度 ,无解。否则一定有解,只要找到 长度不超过 且有最少未赋值的边的路径,然后将这条路径改造成长度为 ,其余未赋值的边一律给 ,这就是一个合法方案,显然不存在不经过未赋值的边且长度小于 的路径,然后任何存在未赋值的边的路径(除了我们选定的路径),长度要么是 ,要么大于等于 (经过且只经过选定的路径上的所有未赋值边),所以一定能构造出可行解,但是我们只用这种方法证明,不用这种方法构造。
正解居然是强行二分!设有 条未赋值的边,随意排列它们,找到最小的 ,使得将 的边赋值 ,其余的边赋值 , 最短路长度 ;且将 的边赋值 ,其余的边赋值 , 最短路长度 ,如果不存在这样一个 ,则不经过这些未赋值的边, 最短路就恰好是 ,正合题意。
现在的情况是,如果第 条边的权值赋为 ,那么最短路长度 ,赋为 ,那么最短路长度 ,只需要调整 的权值,就可以满足题意( 增加一,最短路至多增加 ),所以二分一下 的权值就可以了。
最短路可以使用 Dijkstra 或者 SPFA。如果使用较稳定的 Dijkstra,复杂度:。
代码
// Created by Sengxian on 09/18/16. // Copyright (c) 2016年 Sengxian. All rights reserved. // Codeforces 715B 二分 + 最短路 #include <bits/stdc++.h> using namespace std; typedef long long ll; inline int ReadInt() { static int n, ch; n = 0, ch = getchar(); while (!isdigit(ch)) ch = getchar(); while (isdigit(ch)) n = (n << 3) + (n << 1) + ch - '0', ch = getchar(); return n; } const int MAX_N = 1000 + 3, MAX_M = 10000 + 3; const int INF = 0x3f3f3f3f; struct edge { int from, to, cost, id; edge(int from, int to, int cost, int id): from(from), to(to), cost(cost), id(id) {} edge() {} }edges[MAX_M]; vector<edge> G[MAX_N]; int n, m, L, S, T; int cnt = 0; ll SPFA(int p, ll w) { static int q[MAX_N]; static ll dis[MAX_N]; static bool inq[MAX_N]; int l = 0, r = 0, cost; memset(inq, 0, sizeof inq); memset(dis, 0x3f, sizeof dis); dis[S] = 0, q[r++] = S; while (l != r) { int u = q[l++]; if (l == MAX_N) l = 0; inq[u] = false; for (int i = 0; i < (int)G[u].size(); ++i) { const edge &e = G[u][i]; if (e.cost == 0) { if (e.id == p) cost = w; else if (e.id < p) cost = 1; else cost = INF; } else cost = e.cost; if (dis[e.to] > dis[u] + cost) { dis[e.to] = dis[u] + cost; if (!inq[e.to]) { inq[e.to] = true, q[r++] = e.to; if (r == MAX_N) r = 0; } } } } return dis[T]; } void solve() { int l = -1, r = cnt; while (r - l > 1) { int mid = (l + r) >> 1; if (SPFA(mid, 1) <= L) r = mid; else l = mid; } int p = r; l = 1, r = INF; while (r - l > 1) { int mid = (l + r) >> 1; if (SPFA(p, mid) <= L) l = mid; else r = mid; } puts("YES"); for (int i = 0; i < m; ++i) if (edges[i].cost == 0) printf("%d %d %d\n", edges[i].from, edges[i].to, edges[i].id < p ? 1 : (edges[i].id == p ? l : INF)); else printf("%d %d %d\n", edges[i].from, edges[i].to, edges[i].cost); } int main() { #ifndef ONLINE_JUDGE freopen("test.in", "r", stdin); #endif n = ReadInt(), m = ReadInt(), L = ReadInt(), S = ReadInt(), T = ReadInt(); for (int i = 0; i < m; ++i) { static int u, v, w; u = ReadInt(), v = ReadInt(), w = ReadInt(); edges[i].from = u, edges[i].to = v, edges[i].cost = w; if (w == 0) edges[i].id = cnt++; G[u].push_back(edges[i]), G[v].push_back(edges[i]); swap(G[v].back().from, G[v].back().to); } if (SPFA(-1, 0) < L || SPFA(cnt, 0) > L) puts("NO"); else solve(); return 0; }