AcWing340通信线路(dijkstra+二分)(分层图最短路)
题目地址:https://www.acwing.com/problem/content/342/
题目描述:
在郊区有 N 座通信基站,P 条 双向 电缆,第 i 条电缆连接基站Aii和Bi。
特别地,1 号基站是通信公司的总站,N 号基站位于一座农场中。
现在,农场主希望对通信线路进行升级,其中升级第 i 条电缆需要花费Li。
电话公司正在举行优惠活动。
农产主可以指定一条从 1 号基站到 N 号基站的路径,并指定路径上不超过 K 条电缆,由电话公司免费提供升级服务。
农场主只需要支付在该路径上剩余的电缆中,升级价格最贵的那条电缆的花费即可。
求至少用多少钱可以完成升级。
输入格式
第1行:三个整数N,P,K。
第2..P+1行:第 i+1 行包含三个整数Ai,Bi,Li。
输出格式
包含一个整数表示最少花费。
若1号基站与N号基站之间不存在路径,则输出”-1”。
数据范围
0≤K<N≤1000
1≤P≤10000
1≤Li≤1000000
题解:这道题可以用二分+单源最短路来解决,而且用二分非常巧妙。枚举答案[0,1e6+1],至于这里的答案区间为什么是这样的,后面再解释。假设当前二分的是x,那么便可以求1的单源最短路,并且将边的权值大于x的边的权值看作为1,小于等于x的边的权值看作为0,那么求出的dis[n]就是在答案为x时,最小需要不用付出代价的边的数量,当dis[n]<=k,则x可以满足,那么就可以继续枚举x的左边,否则枚举x的右边。所以最后求出的是最小的一个x使得dis[n]<=k.至于答案区间[0,1e6+10],0是因为可能会出现k大于等于1到n之间的最少的边的数量,1e6+1,因为可能会出现1到n之间并不相通,那么最后的二分答案就是1e+10,然后就直接输出-1
AC代码:
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int N=1010,M=1e4+10; typedef pair<int,int> P; struct node{ int from,to,dis,next; }edge[M*2]; int head[N],cnt=0; void addedge(int u,int v,int w){ cnt++; edge[cnt].from=u; edge[cnt].to=v; edge[cnt].dis=w; edge[cnt].next=head[u]; head[u]=cnt; } bool dijkstra(int x,int n,int k){ int dis[n+10],p[n+10]={0}; memset(dis,0x3f,sizeof(dis)); priority_queue<P,vector<P>,greater<P> > q; q.push(make_pair(0,1)); dis[1]=0; while(!q.empty()){ P now=q.top();q.pop(); int u=now.second,s=now.first,w; if(p[u]) continue; p[u]=1; for(int i=head[u];~i;i=edge[i].next){ if(edge[i].dis>x) w=1; else w=0; if(dis[edge[i].to]>dis[edge[i].from]+w){ dis[edge[i].to]=dis[edge[i].from]+w; q.push(make_pair(dis[edge[i].to],edge[i].to)); } } } if(dis[n]>k) return true; else return false; } int main(){ int n,m,k;cin>>n>>m>>k; int u,v,w; memset(head,-1,sizeof(head)); while(m--){ scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } int l=0,r=1e6+1,mid; while(l<r){ mid=l+r>>1; if(dijkstra(mid,n,k)) l=mid+1; else r=mid; } if(r==1e6+1) cout<<"-1"; else cout<<r; return 0; }
题解:这道题也可以直接使用分层图最短路来解决
AC代码:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=1010,M=1e4+10; struct st{ int from,to,dis,next; }edge[M*2]; int head[M*2],cnt=0,dis[N][N]; struct node{ int j,s,i; node(int s,int i,int j):s(s),i(i),j(j){}; friend bool operator>(node a,node b){ return a.s>b.s; } }; void addedge(int u,int v,int w){ cnt++; edge[cnt].from=u; edge[cnt].to=v; edge[cnt].dis=w; edge[cnt].next=head[u]; head[u]=cnt; } void spfa(int s,int k){ memset(dis,0x3f,sizeof(dis)); priority_queue<node,vector<node>,greater<node> >q; q.push(node(0,s,0)); dis[0][s]=0; while(!q.empty()){ node now=q.top();q.pop(); int u=now.i,j=now.j; for(int i=head[u];~i;i=edge[i].next){ if(dis[j][edge[i].to]>max(dis[j][edge[i].from],edge[i].dis)){ dis[j][edge[i].to]=max(dis[j][edge[i].from],edge[i].dis); q.push(node(dis[j][edge[i].to],edge[i].to,j)); } if(j<k&&dis[j+1][edge[i].to]>dis[j][u]){ dis[j+1][edge[i].to]=dis[j][u]; q.push(node(dis[j+1][edge[i].to],edge[i].to,j+1)); } } } } int main(){ int n,m,k;cin>>n>>m>>k; int u,v,w; memset(head,-1,sizeof(head)); while(m--){ scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } spfa(1,k); int minn=0x3f3f3f3f; for(int i=0;i<=k;i++){ minn=min(minn,dis[i][n]); } if(minn==0x3f3f3f3f) cout<<"-1"; else cout<<minn; return 0; }
写于:2020/9/5 16:51
作者:孙建钊
出处:http://www.cnblogs.com/sunjianzhao/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。