main
黄海 2 years ago
parent 2450132632
commit 80dcfe0412

@ -8,39 +8,44 @@ int idx, h[N], e[M], w[M], ne[M];
void add(int a, int b, int c) { void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++; e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
} }
int n; //点数 int n; // 点数
int m; //边数 int m; // 边数
bool st[N]; //记录是不是在队列中
int k; //不超过K条电缆由电话公司免费提供升级服务 int k; // 不超过K条电缆由电话公司免费提供升级服务
int dist[N]; //记录最短距离
// u指的是我们现在选最小花费 bool st[N]; // 记录是不是在队列中
bool check(int x) { int dis[N]; // 记录最短距离
// mid指的是我们现在选最小花费
bool check(int mid) {
// 需要跑多次dijkstra所以需要清空状态数组
memset(st, false, sizeof st); memset(st, false, sizeof st);
memset(dist, 0x3f, sizeof dist); memset(dis, 0x3f, sizeof dis);
priority_queue<PII, vector<PII>, greater<PII>> q; priority_queue<PII, vector<PII>, greater<PII>> q;
dist[1] = 0; dis[1] = 0;
q.push({0, 1}); q.push({0, 1});
while (q.size()) { while (q.size()) {
PII t = q.top(); PII t = q.top();
q.pop(); q.pop();
int d = t.first, u = t.second; int u = t.second;
if (st[u]) continue; if (st[u]) continue;
st[u] = true; st[u] = true;
for (int i = h[u]; ~i; i = ne[i]) { for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i], v = w[i] > x; //如果有边比我们现在选的这条边大那么这条边对方案的贡献为1反之为0 int j = e[i];
if (dist[j] > d + v) { int v = w[i] > mid; // 如果有边比我们现在选的这条边大那么这条边对方案的贡献为1反之为0
dist[j] = d + v; if (dis[j] > dis[u] + v) {
q.push({dist[j], j}); dis[j] = dis[u] + v;
q.push({dis[j], j});
} }
} }
} }
//如果按上面的方法计算后n结点没有被松弛操作修改距离则表示n不可达 // 如果按上面的方法计算后n结点没有被松弛操作修改距离则表示n不可达
if (dist[n] == INF) { if (dis[n] == INF) {
puts("-1"); //不可达,直接输出-1 puts("-1"); // 不可达,直接输出-1
exit(0); exit(0);
} }
return dist[n] <= k; //如果有k+1条边比我们现在这条边大那么这个升级方案就是不合法的反之就合法 return dis[n] <= k; // 如果有k+1条边比我们现在这条边大那么这个升级方案就是不合法的反之就合法
} }
int main() { int main() {
memset(h, -1, sizeof h); memset(h, -1, sizeof h);
@ -50,11 +55,12 @@ int main() {
cin >> a >> b >> c; cin >> a >> b >> c;
add(a, b, c), add(b, a, c); add(a, b, c), add(b, a, c);
} }
/*这里二分的是直接面对答案设问:最少花费 /*
k+1 k+1
k+1(k+1),0 k+1(k+1),0
1e6 1e6,,:0 ~ 1e6
0 ~ 1e6*/ */
int l = 0, r = 1e6; int l = 0, r = 1e6;
while (l < r) { while (l < r) {
int mid = (l + r) >> 1; int mid = (l + r) >> 1;

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

Loading…
Cancel
Save