题面:
P1948 [USACO08JAN]Telephone Lines S
思路:
贪心的想,如果一条简单路径中,把免费的K段都给了权值最大的K条边,那么第K+1条边肯定是最优的
考虑二分答案,SPFA维护到$n$点的花费免费路线最少的路线,如果这个当前选取的边大于当前所二分判断的长度$x$,那么$dis[to]=dis[cur]+1$,否则$dis[to]=dis[cur]$,最后再判断$dis[n] leq k$是否成立。
代码:
1 #include <bits/stdc++.h> 2 3 #define debug(...) fprintf(stderr,__VA_ARGS__) 4 #define DEBUG printf("Passing [%s] in LINE %d ",__FUNCTION__,__LINE__) 5 #define Debug debug("Passing [%s] in LINE %d ",__FUNCTION__,__LINE__) 6 #define rep(i,x,y) for(int i=(x);i<=(y);++i) 7 8 using namespace std; 9 typedef long long ll; 10 typedef unsigned long long ull; 11 typedef pair<int,int> pii; 12 typedef pair<ll,int> pli; 13 typedef pair<int,ll> pil; 14 typedef pair<ll,ll> pll; 15 16 const ll MOD=1e9+7; 17 const int INF=0x3f3f3f3f; 18 const int MAXN=1010; 19 ll qpow(ll a,ll b){ll ret=1;for(;b;b>>=1) if(b&1) ret=ret*a%MOD,a=a*a%MOD;return ret;} 20 21 int n,p,k; 22 23 vector<pii> g[MAXN]; 24 int dis[MAXN],inq[MAXN]; 25 26 27 bool chk(int val){ 28 queue<int> q; 29 memset(dis,0x3f,sizeof(dis)); 30 dis[1]=0; 31 q.push(1); 32 inq[1]=1; 33 while(!q.empty()){ 34 int u=q.front(); 35 q.pop(); 36 inq[u]=0; 37 for(int i=0;i<g[u].size();++i){ 38 int to=g[u][i].second,v=g[u][i].first; 39 int s; 40 if(v>val) s=dis[u]+1; 41 else s=dis[u]; 42 if(dis[to]>s){ 43 dis[to]=s; 44 if(!inq[to]){ 45 inq[to]=1; 46 q.push(to); 47 } 48 } 49 50 } 51 } 52 if(dis[n]<=k) return 1; 53 return 0; 54 } 55 56 57 int main(){ 58 cin>>n>>p>>k; 59 int u,v,w; 60 int r=0; 61 rep(i,1,p) scanf("%d%d%d",&u,&v,&w),g[u].push_back({w,v}),g[v].push_back({w,u}),r=max(r,w); 62 int l=0; 63 int fl=0; 64 while(l<r){ 65 int mid=(l+r)>>1; 66 if(chk(mid)) r=mid,fl=1; 67 else l=mid+1; 68 } 69 if(!fl){ 70 cout<<"-1"; 71 return 0; 72 } 73 cout<<l; 74 return 0; 75 }