P1948 [USACO08JAN] Telephone Lines S 二分+最短路

原题链接 参考文章

题意:给你n个点的图,有p个边,要从1到n点走一条路,价格是路上最大的边权,而且给你k个免费的,求最小价格。

一开始就想到二分价格,但是没想到怎么很好地找出最优的路径。

题解很巧妙:把边权>mid的边数作为权为1的边,其余边为0。

因为这样就能算出“最少减免边数”从而判断是否合法(在k个以内)。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define endl '\n'
#define fff(x,y,z) for(int x=(y);x<=(z);x++)
#define pii pair<int,int>
 const int MAX=1e3+2;
// const int MOD;
int N,M,K;
vector<pii> e[MAX];
int fa[MAX];
struct last{
	int fa,w;
}ll[MAX];
bool vv[MAX];
int dijk(int s,int n,int limit){
	vector<int> dis(n+1,LONG_MAX);
	priority_queue<pii,vector<pii >,greater<pii > > pq;
	vector<int> vis(n+1,false);
	dis[s]=0;
	pq.push({0,s});
	while(pq.size()){
		auto [dist,idx]=pq.top();
		pq.pop();
		//if(idx==n)break;
		if(vis[idx])continue;
		vis[idx]=1;
		for(auto [v,w]:e[idx]){
//			w=get_w(idx,v,w);
			w=(w>limit)?1:0;
			if(dis[v]>dist+w){
				dis[v]=dist+w;
				pq.push({dis[v],v});
			}
		}
	}
	return dis[n];
}
bool check(int x){
	if(dijk(1,N,x)<=K)return 1;
	return 0;
}
void dfs(int cur){
	if(vv[cur])return;
	vv[cur]=1;
	for(auto [v,w]:e[cur]){
		dfs(v);
	}
};
void solve(){
	cin>>N>>M>>K;
	int L=0,R=-1;
	fff(i,1,M){
		int u,v,w;
		cin>>u>>v>>w;
		R=max(R,w);
		e[u].emplace_back((pii){v,w});
		e[v].emplace_back((pii){u,w});
	}
//	vector<bool> vv(N+2);
//	function<void(int)> dfs;
	dfs(1);
	if(!vv[N]){cout<<-1<<endl;return;}
//	dijk(1,N);
	R++;
	while(L+1!=R){
		int mid=(L+R)/2;
		if(check(mid))R=mid;
		else L=mid;
	}
	cout<<R<<endl;
}
signed main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	// int times;cin>>times;
	// while(times--)
	solve();
	return 0;
}
posted @ 2025-08-18 23:27  Treow  阅读(12)  评论(0)    收藏  举报