题解 P1948 【[USACO08JAN]电话线Telephone Lines】
比较套路的一道题。
首先可以想到是要二分这个费用,然后我们思考如何check他合不合法。
一个比较妙的思路就是,我们把整个图上所有大于mid的边赋为0,所有小于等于mid的边赋值为1,这样的话只需要跑一边
时间复杂度
#include <bits/stdc++.h>
using namespace std;
int n , p , k, ans=-1;
int l = 1, r;
const int N = 1e4 + 10;
struct Edge {
int to , nxt , w;
}e[N << 1];
int head[N] , cnt;
void add(int u , int v ,int w) {
e[++ cnt].to = v;
e[cnt].w = w;
e[cnt].nxt = head[u];
head[u] = cnt;
}
bool inq[N];
int dis[N];
bool check(int x) {
queue <int> q;
q.push(1);
for(int i = 2 ; i <= n ; ++ i) dis[i] = 0x3f3f3f3f;
inq[1] = 1; dis[1] = 0;
while(!q.empty()) {
int now = q.front(); q.pop();
inq[now] = 0;
for(int i = head[now] ; i ; i = e[i].nxt) {
int v = e[i].to , w = e[i].w;
if(w <= x) w = 0;
else w = 1;
if(dis[v] > dis[now] + w) {
dis[v] = dis[now] + w;
if(!inq[v]) inq[v] = 1 , q.push(v);
}
}
}
return dis[n] <= k;
}
int main () {
scanf("%d %d %d" , &n , &p , &k);
for(int i = 1 ; i <= p ; ++ i) {
int u , v , w;
scanf("%d %d %d" , &u , &v, &w);
add(u , v , w); add(v , u , w);
r += w;
}
while(l <= r) {
int mid = (l + r) >> 1;
if(check(mid)) ans = mid , r = mid - 1;
else l = mid + 1;
}
printf("%d\n" , ans);
return 0;
}