通信线路
题意
给定一个无向图,可以选择一条线路,将其 k k k条边边权变为 0 0 0,使得剩下边的边权最大值最小。求这个最小值。
做法
一看最大值最小,首先考虑二分,二分答案。二分过程中,如果大于 m i d mid mid的边数大于 k k k,那么这个最小值一定大于当前二分到的答案。
代码1(Dijkstra)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1010, M = 20010, inf = 0x3f3f3f3f;
typedef pair<int,int> pii;
int n,m,k;
int h[N], e[M], ne[M], w[M], idx;
int dist[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
bool check(int limit)
{
memset(dist,0x3f,sizeof(dist));
memset(st,false,sizeof(st));
dist[1] = 0;
priority_queue<pii,vector<pii>,greater<pii>> heap;
heap.push({
0,1});
while(heap.size()){
auto t = heap.top();
heap.pop();
int ver = t.second, distance = t.first;
if(st[ver]) continue;
st[ver] = true;
for(int i=h[ver];~i;i=ne[i]){
int j = e[i];
int x = w[i] > limit;
if(dist[j]>distance+x){
dist[j] = distance + x;
heap.push({
dist[j],j});
}
}
}
return dist[n] <= k;
}
int main()
{
cin >> n >> m >> k;
memset(h,-1,sizeof(h));
while(m--){
int a,b,c;
cin >> a >> b >> c;
add(a,b,c), add(b,a,c);
}
int l = 0, r = 1e6 + 1;
while(l<r){
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
if(r==1e6+1) cout << -1 << endl;
else cout << r << endl;
return 0;
}
代码2(spfa)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1010, M = 20010, inf = 0x3f3f3f3f;
int n,m,k;
int h[N], e[M], ne[M], w[M], idx;
int dist[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
bool check(int limit)
{
memset(dist,0x3f,sizeof(dist));
memset(st,false,sizeof(st));
dist[1] = 0;
queue<int> que;
que.push(1);
st[1] = true;
while(que.size()){
int t = que.front();
que.pop();
st[t] = false;
for(int i=h[t];~i;i=ne[i]){
int j = e[i];
int distance = w[i] > limit;
if(dist[j]>dist[t]+distance){
dist[j] = dist[t] + distance;
if(!st[j]){
st[j] = true;
que.push(j);
}
}
}
}
return dist[n] <= k;
}
int main()
{
cin >> n >> m >> k;
memset(h,-1,sizeof(h));
while(m--){
int a,b,c;
cin >> a >> b >> c;
add(a,b,c), add(b,a,c);
}
int l = 0, r = 1e6 + 1;
while(l<r){
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
if(r==1e6+1) cout << -1 << endl;
else cout << r << endl;
return 0;
}