题目链接:https://www.luogu.com.cn/problem/P1948
这道题的题意大体是:求原点1到n的所有路中的第k+1长的路最小。
这道题的思路比较好:
首先,是最大值最小的问题,会用到二分答案。
其次,要将前k大的路免费掉,那么可以将大于二分值的路径长度设为1,将小于二分值的路径长度设为0,这样等于跑一边0/1最短路,如果dis[n]<=k,那说明在限制条件之内,可以继续缩小二分范围。否则说明无法满足。
AC代码:
#include<cstdio> #include<iostream> #include<cstring> #include<queue> using namespace std; const int N=10005; queue<int> q; struct node{ int to,next,w; }edge[N<<1]; int head[N],dis[N],vis[N]; int n,p,m,tot,k; void add(int u,int v,int w){ edge[tot].next=head[u]; edge[tot].to=v; edge[tot].w=w; head[u]=tot++; } bool check(int u,int v){ return u>v; } bool spfa(int x){ memset(dis,0x3f3f,sizeof(dis)); while(!q.empty()) q.pop(); q.push(1); dis[1]=0; vis[1]=1; while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(dis[v]>dis[u]+check(edge[i].w,x)){ dis[v]=dis[u]+check(edge[i].w,x); if(!vis[v]) q.push(v),vis[v]=1; } } } if(dis[n]<=k) return 1; return 0; } int main(){ memset(head,-1,sizeof(head)); scanf("%d%d%d",&n,&p,&k); for(int i=1;i<=p;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); } //printf("-1"); int ans=-1; int l=0,r=1000000; while(l<=r){ int m=(l+r)>>1; //printf("-1"); if(spfa(m)) {ans=m; r=m-1;} else l=m+1; } printf("%d",ans); return 0; }