diff --git a/TangDou/AcWing_TiGao/T3/MiniPathYingYong/340.cpp b/TangDou/AcWing_TiGao/T3/MiniPathYingYong/340.cpp index b095692..e359dfe 100644 --- a/TangDou/AcWing_TiGao/T3/MiniPathYingYong/340.cpp +++ b/TangDou/AcWing_TiGao/T3/MiniPathYingYong/340.cpp @@ -8,39 +8,44 @@ int idx, h[N], e[M], w[M], ne[M]; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++; } -int n; //点数 -int m; //边数 -bool st[N]; //记录是不是在队列中 -int k; //不超过K条电缆,由电话公司免费提供升级服务 -int dist[N]; //记录最短距离 -// u指的是我们现在选最小花费 -bool check(int x) { +int n; // 点数 +int m; // 边数 + +int k; // 不超过K条电缆,由电话公司免费提供升级服务 + +bool st[N]; // 记录是不是在队列中 +int dis[N]; // 记录最短距离 + +// mid指的是我们现在选最小花费 +bool check(int mid) { + // 需要跑多次dijkstra,所以需要清空状态数组 memset(st, false, sizeof st); - memset(dist, 0x3f, sizeof dist); + memset(dis, 0x3f, sizeof dis); priority_queue, greater> q; - dist[1] = 0; + dis[1] = 0; q.push({0, 1}); while (q.size()) { PII t = q.top(); q.pop(); - int d = t.first, u = t.second; + int u = t.second; if (st[u]) continue; st[u] = true; for (int i = h[u]; ~i; i = ne[i]) { - int j = e[i], v = w[i] > x; //如果有边比我们现在选的这条边大,那么这条边对方案的贡献为1,反之为0 - if (dist[j] > d + v) { - dist[j] = d + v; - q.push({dist[j], j}); + int j = e[i]; + int v = w[i] > mid; // 如果有边比我们现在选的这条边大,那么这条边对方案的贡献为1,反之为0 + if (dis[j] > dis[u] + v) { + dis[j] = dis[u] + v; + q.push({dis[j], j}); } } } - //如果按上面的方法计算后,n结点没有被松弛操作修改距离,则表示n不可达 - if (dist[n] == INF) { - puts("-1"); //不可达,直接输出-1 + // 如果按上面的方法计算后,n结点没有被松弛操作修改距离,则表示n不可达 + if (dis[n] == INF) { + puts("-1"); // 不可达,直接输出-1 exit(0); } - return dist[n] <= k; //如果有k+1条边比我们现在这条边大,那么这个升级方案就是不合法的,反之就合法 + return dis[n] <= k; // 如果有k+1条边比我们现在这条边大,那么这个升级方案就是不合法的,反之就合法 } int main() { memset(h, -1, sizeof h); @@ -50,11 +55,12 @@ int main() { cin >> a >> b >> c; add(a, b, c), add(b, a, c); } - /*这里二分的是直接面对答案设问:最少花费 + /* + 这里二分的是直接面对答案设问: 至少用多少钱 可以完成升级 依题意,最少花费其实是所有可能的路径中,第k+1条边的花费 如果某条路径不存在k+1条边(边数小于k+1),此时花费为0 - 同时,任意一条边的花费不会大于1e6 - 整理一下,这里二分枚举的值其实是0 ~ 1e6*/ + 同时,任意一条边的花费不会大于1e6,所以,这里二分枚举范围:0 ~ 1e6 + */ int l = 0, r = 1e6; while (l < r) { int mid = (l + r) >> 1; diff --git a/TangDou/AcWing_TiGao/T3/MiniPathYingYong/340.md b/TangDou/AcWing_TiGao/T3/MiniPathYingYong/340.md index 9685aed..e5ccee9 100644 --- a/TangDou/AcWing_TiGao/T3/MiniPathYingYong/340.md +++ b/TangDou/AcWing_TiGao/T3/MiniPathYingYong/340.md @@ -75,7 +75,7 @@ $0≤K using namespace std; @@ -87,39 +87,44 @@ int idx, h[N], e[M], w[M], ne[M]; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++; } -int n; //点数 -int m; //边数 -bool st[N]; //记录是不是在队列中 -int k; //不超过K条电缆,由电话公司免费提供升级服务 -int dist[N]; //记录最短距离 -// u指的是我们现在选最小花费 -bool check(int x) { +int n; // 点数 +int m; // 边数 + +int k; // 不超过K条电缆,由电话公司免费提供升级服务 + +bool st[N]; // 记录是不是在队列中 +int dis[N]; // 记录最短距离 + +// mid指的是我们现在选最小花费 +bool check(int mid) { + // 需要跑多次dijkstra,所以需要清空状态数组 memset(st, false, sizeof st); - memset(dist, 0x3f, sizeof dist); + memset(dis, 0x3f, sizeof dis); priority_queue, greater> q; - dist[1] = 0; + dis[1] = 0; q.push({0, 1}); while (q.size()) { PII t = q.top(); q.pop(); - int d = t.first, u = t.second; + int u = t.second; if (st[u]) continue; st[u] = true; for (int i = h[u]; ~i; i = ne[i]) { - int j = e[i], v = w[i] > x; //如果有边比我们现在选的这条边大,那么这条边对方案的贡献为1,反之为0 - if (dist[j] > d + v) { - dist[j] = d + v; - q.push({dist[j], j}); + int j = e[i]; + int v = w[i] > mid; // 如果有边比我们现在选的这条边大,那么这条边对方案的贡献为1,反之为0 + if (dis[j] > dis[u] + v) { + dis[j] = dis[u] + v; + q.push({dis[j], j}); } } } - //如果按上面的方法计算后,n结点没有被松弛操作修改距离,则表示n不可达 - if (dist[n] == INF) { - puts("-1"); //不可达,直接输出-1 + // 如果按上面的方法计算后,n结点没有被松弛操作修改距离,则表示n不可达 + if (dis[n] == INF) { + puts("-1"); // 不可达,直接输出-1 exit(0); } - return dist[n] <= k; //如果有k+1条边比我们现在这条边大,那么这个升级方案就是不合法的,反之就合法 + return dis[n] <= k; // 如果有k+1条边比我们现在这条边大,那么这个升级方案就是不合法的,反之就合法 } int main() { memset(h, -1, sizeof h); @@ -129,11 +134,12 @@ int main() { cin >> a >> b >> c; add(a, b, c), add(b, a, c); } - /*这里二分的是直接面对答案设问:最少花费 + /* + 这里二分的是直接面对答案设问: 至少用多少钱 可以完成升级 依题意,最少花费其实是所有可能的路径中,第k+1条边的花费 如果某条路径不存在k+1条边(边数小于k+1),此时花费为0 - 同时,任意一条边的花费不会大于1e6 - 整理一下,这里二分枚举的值其实是0 ~ 1e6*/ + 同时,任意一条边的花费不会大于1e6,所以,这里二分枚举范围:0 ~ 1e6 + */ int l = 0, r = 1e6; while (l < r) { int mid = (l + r) >> 1;