最短路的一个变种
题目大意:
目前在一个很大的平面房间里有 n 个无线路由器,每个无线路由器都固定在某个点上。任何两个无线路由器只要距离不超过 r 就能互相建立网络连接。
除此以外,另有 m 个可以摆放无线路由器的位置。你可以在这些位置中选择至多 k 个增设新的路由器。
你的目标是使得第 1 个路由器和第 2 个路由器之间的网络连接经过尽量少的中转路由器。请问在最优方案下中转路由器的最少个数是多少?
刚看到这个题的时候先是懵逼,后来发现这就是一个最短路变种,主要是有个条件是不能在新位置添加超过k个结点,这个问题可以转换为用迪杰斯特拉求最短路的时候并且考虑一下当前这个最优结点是不是已经经过了k个新的路由器,如果当前的结点已经经过了k个新路由器那么这个最优结点显然不能更新后继结点的,那么只能选择其他结点,但是又发现边权是1,那么久变成了01最短路,可以队列直接做,时间复杂度是o(n)的
代码:
#include <iostream> #include <cmath> #include <cstring> #include <queue> using namespace std; const int N =300; typedef long long ll; int dis[N],cnt[N]; int edg[N][N]; int vi[N]; pair<ll,ll>node[N]; double get_dis(pair<ll,ll> a,pair<ll,ll> b){ int x1=a.first,y1=a.second; int x2=b.first,y2=b.second; return sqrt((x1-x2)*1.0*(x1-x2)+(y1-y2)*1.0*(y1-y2)); } int main(){ int n,m,k,r; cin>>n>>m>>k>>r; memset(edg,0,sizeof edg); memset(vi,0,sizeof vi); memset(dis,0x3f,sizeof dis); for(int i=0;i<n;i++){ cin>>node[i].first>>node[i].second; } for(int i=0;i<m;i++){ cin>>node[n+i].first>>node[n+i].second; } for(int i=0;i<n+m;i++){ for(int j=i+1;j<n+m;j++){ if(get_dis(node[i],node[j])<=1.0*r){ edg[i][j]=1; edg[j][i]=1; } } } vi[0]=1; dis[0]=0; queue<int> q; for(int i=0;i<n+m;i++){ if(vi[i])continue; if(edg[0][i]){ dis[i]=0; cnt[i]=0; q.push(i); vi[i]=1; } } while(q.size()){ int minid=q.front(); q.pop(); if(cnt[minid]>k)continue; if(minid>=n){ for(int j=0;j<n+m;j++){ if(vi[j])continue; if(edg[minid][j]){ q.push(j); dis[j]=dis[minid]+1; vi[j]=1; cnt[j]++; } } } else { for(int j=0;j<n+m;j++){ if(vi[j])continue; if(edg[minid][j]){ q.push(j); dis[j]=dis[minid]+1; vi[j]=1; } } } } cout<<dis[1]<<endl; }

浙公网安备 33010602011771号