问题描述
目前在一个很大的平面房间里有 n 个无线路由器,每个无线路由器都固定在某个点上。任何两个无线路由器只要距离不超过 r 就能互相建立网络连接。
除此以外,另有 m 个可以摆放无线路由器的位置。你可以在这些位置中选择至多 k 个增设新的路由器。
你的目标是使得第 1 个路由器和第 2 个路由器之间的网络连接经过尽量少的中转路由器。请问在最优方案下中转路由器的最少个数是多少?
输入格式
第一行包含四个正整数 n,m,k,r。(2 ≤ n ≤ 100,1 ≤ k ≤ m ≤ 100, 1 ≤ r ≤ 108)。
接下来 n 行,每行包含两个整数 xi 和 yi,表示一个已经放置好的无线 路由器在 (xi, yi) 点处。输入数据保证第 1 和第 2 个路由器在仅有这 n 个路由器的情况下已经可以互相连接(经过一系列的中转路由器)。
接下来 m 行,每行包含两个整数 xi 和 yi,表示 (xi, yi) 点处可以增设 一个路由器。
输入中所有的坐标的绝对值不超过 108,保证输入中的坐标各不相同。
输出格式
输出只有一个数,即在指定的位置中增设 k 个路由器后,从第 1 个路 由器到第 2 个路由器最少经过的中转路由器的个数。
样例输入
5 3 1 3
0 0
5 5
0 3
0 5
3 5
3 3
4 4
3 0
样例输出
2
Java 代码 :
package csp201403;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
public class WirelessNet {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int n=sc.nextInt();//目前在一个很大的平面房间里有 n 个无线路由器
int m=sc.nextInt();//有 m 个可以摆放无线路由器的位置
int k=sc.nextInt();//可以在这些位置中选择至多 k 个增设新的路由器。
long r=sc.nextLong();//任何两个无线路由器只要距离不超过 r 就能互相建立网络连接
Node node[]=new Node[n+m];//注意是n+m。
for(int i=0;i<node.length;i++) {
node[i]=new Node(sc.nextLong(),sc.nextLong(),i);
}
boolean vis[][]=new boolean[n+m][n+m];
Queue<Node> q = new LinkedList<Node>();
q.add(node[0]);
while(!q.isEmpty()) {
Node no=q.poll();
int ti=no.time;
int add=no.newAdd;
int num=no.num;
if(num==1) {//如果访问到第二个顶点(下标为1的顶点),则输出经过的中转路由器的个数。
System.out.println(ti-1);
return ;
}
for(int i=1;i<node.length;i++) {
//循环从i=1开始。这个是有必要的,但是我描述不清楚,抱歉。当然,你从0开始遍历也可以,但是这样可以缩短程序运行时间
if(node[i].distance(no)<=r&&num!=i) {
//如果num!-i 因为加入poll出来的Node 假如num为5,而你计算node[5]到node[5]的距离是没用的,没有必要把自己加入队列,加入只会增加程序运行时间。
if(vis[i][num]==true) {//如果num 点已经通过i点加入到队列中,那么应该continue
continue;
}
if(i<n&&add<=k) {
q.add(new Node(node[i].x,node[i].y,ti+1,add,i));
}
else if(i>=n&&add+1<=k){//如果i>=n,说明是新设的点,所以应该add+
q.add(new Node(node[i].x,node[i].y,ti+1,add+1,i));
}
else {
continue;
}
vis[i][num]=true;
vis[num][i]=true;
}
}
}
}
}
class Node{
int num;//编号
long x;//x坐标
long y;//y坐标
int time;//已经走过的步数
int newAdd;//到达这个点所经过的新设路由器
public Node(long x, long y,int num) {
this.num=num;
this.x = x;
this.y = y;
time=0;
newAdd=0;
}
public Node(long x, long y, int time, int newAdd,int num) {
this.x = x;
this.y = y;
this.time = time;
this.newAdd = newAdd;
this.num=num;
}
public double distance(Node n) {
long t1=n.x-x;
long t2=n.y-y;
return Math.sqrt(t1*t1+t2*t2);
}
}
如果看不懂,那就调试吧。调试是最后的理解程序的方法。
用Eclipse调试的时候,按F5的话是程序运行下一行,但是如果下一行调用了函数,它会跳到函数里面。按F6的话,也是运行下一行,但是如果有程序调用,他不会跳到被调用的函数里面。