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;
}

浙公网安备 33010602011771号