201703-4 地铁维修


思路

这道题是求最大值最小,所以很明显又是要用二分。自己没注意到是因为没有注意到所选边数小于等于n这个事,所以理解题意呀!
每次二分得到一个距离mid,如果能选不超过n条边,使得每条边的权值都小于mid,那么这个值就可以选。
由于这里只涉及边的个数,所以所有边的权都变成1了,所以用bfs+松弛操作就好了。

代码:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int N = 1e5 + 5;
const int M = 4*N;
int h[N], e[M], ne[M], w[M], idx;
int d[N];
void add(int a, int b ,int c){
	 e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int n,m;
inline int read(){//读优化,没有这个90分
    	int x=0,f=1;
    	char c=getchar();//scanf函数比getchar函数慢不少,当需要大量输入数据时可考虑优化
    	while(c>'9'||c<'0'){
    		if(c=='-') f=-f;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x*f;
}
int bfs(int mid){
	memset(d, 0x3f, sizeof(d));
	queue q;
	d[1] = 0;
	q.push(1);
	while(q.size()){
		int t = q.front();
		q.pop();
		for(int i = h[t]; i != -1;i = ne[i]){
			if(w[i] > mid)continue;
			int j = e[i];
			if(d[j] > d[t] + 1){
				d[j] = d[t] + 1;
				q.push(j); 
			}
		}
	}
	return d[n];
}
int main(){
	memset(h, -1, sizeof(h));
	n = read(), m = read();
	while(m--){
		int a,b,c;
		a = read(), b = read(), c = read();
		add(a, b ,c);
		add(b, a, c);
	}
	int l = 0, r = 1e6;
	while(l < r){
		int mid = (l + r) / 2;
		if(bfs(mid) <= n){
			r = mid;
		}else{
			l = mid + 1;
		}
	}
	cout<
csp