题目链接:洛谷P1948[USACO08JAN]电话线Telephone Lines
分析:
题意:在无向图中找到一条路径,可以使k条边花费0,最后花费即为剩下的边中最大值,使这个最大值最小。
1.使最大值最小的问题明显可以二分一个mid。
2.由贪心可知,使k条花费为0必然是最大的k条边,即要求的值是路径中第k+1大的路径长度。
那么我们现在二分了一个值了,怎么check路径上是否有<=k条边小于mid呢?当然是规避比mid大的边走啦。
通过把>mid的边设成1,<=mid的边设成0,跑最短路
//洛谷P1948 #include<bits/stdc++.h> using namespace std; #define N 1005 #define M 20005 int head[N],val[M],nex[M],to[M],w[M],dis[N],vis[N]; int tot=0,n,k; void add(int a,int b,int ww){ to[++tot]=b; nex[tot]=head[a]; head[a]=tot; val[tot]=ww; } struct pack{ int s,dis; }; priority_queue<pack> q; bool operator < (const pack &a,const pack &b){ return a.dis>b.dis; } int dij() { memset(dis,0x7f7f7f,sizeof(dis)); memset(vis,0,sizeof(vis)); int s=1,t=n; dis[s]=0; q.push((pack){s,dis[s]}); while(!q.empty()){ pack t=q.top(); q.pop(); int u=t.s; if(vis[u]) continue; vis[u]=1; for(int i=head[u];i;i=nex[i]){ int v=to[i]; if(dis[v]>dis[u]+w[i]){ dis[v]=dis[u]+w[i]; if(!vis[v]) q.push((pack){v,dis[v]}); } } } return dis[t]; } bool check(int x) { memset(w,0,sizeof(w)); for(int i=1;i<=tot;i++) if(val[i]>x) w[i]=1; int diss=dij(); if(diss<=k) return true; if(diss==2139062143) { printf("-1"); exit(0); } return false; } int main() { int m,a,b,c,maxn=0,ans=0; scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=m;i++){ scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); maxn=max(maxn,c); } int l=0,r=maxn; while(l<r){ int mid=(l+r)>>1; if(!check(mid)) l=mid+1; else r=mid,ans=mid; } printf("%d\n",ans); return 0; } /* 6 7 2 1 2 5 3 1 4 2 4 8 3 2 3 5 2 9 3 4 7 4 5 6 */