P1948 [USACO08JAN]Telephone Lines S

P1948 [USACO08JAN]Telephone Lines S

这种题显然考虑二分(有条件最大值最小(确信)。

然后发现可以二分,那么直接二分跑dijk/spfa/0-1bfs。

为啥啊,因为,肯定是要选够 \(K\) 条的。所以我们二分一下第 \(K-1\) 条边长。大于的都设 \(1\) 小于等于的都设 \(0\)。分别代表需要一个代价去免费它或者需要自己付款。

然后就是答案了。

/*
	Name:
	Author: Gensokyo_Alice
	Date:
	Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10, INF = 0x3f3f3f3f3f3f3f3f;

ll head[MAXN], cnt = -1, N, M, KK, hd[MAXN], ck = -1, dis[MAXN], vis[MAXN];

struct edge {
	ll nt, to, v;
} E[MAXN], K[MAXN];

struct heap {
	ll now, val;
	heap(){}
	heap(ll _now, ll _val): now(_now), val(_val) {}
	friend bool operator < (heap a, heap b) {return a.val > b.val;}
};

void add_K(ll, ll, ll);
void add(ll, ll, ll);
ll check(ll);

int main() {
	memset(hd, -1, sizeof(hd));
	scanf("%lld%lld%lld", &N, &M, &KK);
	for (ll i = 1, x, y, v; i <= M; i++) {
		scanf("%lld%lld%lld", &x, &y, &v);
		add_K(x, y, v);
		add_K(y, x, v);
	}
	ll l = 0, r = MAXN, ans = -1;
	while (l <= r) {
		ll mid = (l + r) >> 1;
		if (check(mid) <= KK) {
			r = mid - 1;
			ans = mid;
		} else l = mid + 1;
	}
	printf("%lld", ans);
    return 0;
}

ll check(ll tem) {
	for (ll i = 0; i < N + 10; i++) head[i] = -1;
	for (ll i = 1; i <= N; i++) {
		for (ll j = hd[i]; ~j; j = K[j].nt) {
			ll v = K[j].to;
			add(i, v, K[j].v > tem);
		}
	}
	for (ll i = 0; i < N + 10; i++) dis[i] = INF, vis[i] = 0;
	vis[1] = 1, dis[1] = 0;
	priority_queue <heap> q;
	q.push(heap(1, 0));
	while (!q.empty()) {
		heap nt = q.top(); q.pop();
		if (nt.val > dis[nt.now]) continue;
		for (ll i = head[nt.now]; ~i; i = E[i].nt) {
			ll v = E[i].to;
			if (dis[v] > dis[nt.now] + E[i].v) {
				dis[v] = dis[nt.now] + E[i].v;
				q.push(heap(v, dis[v]));
			}
		}
	}
	return dis[N];
}

void add(ll x, ll y, ll v) {
	cnt++;
	E[cnt].v = v;
	E[cnt].to = y;
	E[cnt].nt = head[x];
	head[x] = cnt;
}

void add_K(ll x, ll y, ll v) {
	ck++;
	K[ck].v = v;
	K[ck].to = y;
	K[ck].nt = hd[x];
	hd[x] = ck;
}

posted @ 2020-11-17 11:25  Gensokyo_Alice  阅读(83)  评论(0编辑  收藏  举报