CCF201403 无线网络【限制型最短路】
问题描述
目前在一个很大的平面房间里有 n 个无线路由器,每个无线路由器都固定在某个点上。任何两个无线路由器只要距离不超过 r 就能互相建立网络连接。
除此以外,另有 m 个可以摆放无线路由器的位置。你可以在这些位置中选择至多 k 个增设新的路由器。
你的目标是使得第 1 个路由器和第 2 个路由器之间的网络连接经过尽量少的中转路由器。请问在最优方案下中转路由器的最少个数是多少?
除此以外,另有 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,保证输入中的坐标各不相同。
接下来 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
0 0
5 5
0 3
0 5
3 5
3 3
4 4
3 0
样例输出
2
题解思路:
1.首先建图,对于任意两个距离小于 r 的点连无向边。边权设为 1。当找到1与2的最短路,那么中转的点的数量就是dis[2] - 1。
2.因为是在m个点选择k个点增设。那么每次从队列中选择一个点进行松弛的时候,要判断 to 的编号是否大于 n ,以及目前已经选择了多少个点,不得超过k。
3.用vis[][]二维数组来记录状态,表示 i 点在已经选择增设了 k 个点的情况下 是否存在于队列中。
4.需要注意在比较距离是否小于r时,数据会爆int。要先转化成ll型或者直接开ll型的数组。
代码如下:
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #define mem(a, b) memset(a, b, sizeof(a)) 5 typedef long long ll; 6 using namespace std; 7 const int MAXN = 210; 8 const int inf = 0x3f3f3f3f; 9 10 int n, m, k; 11 ll r; //n + m个点 其中 m 个点是可选择添入的 最后可增设其中 k 个点。 12 ll x[MAXN], y[MAXN]; 13 int head[MAXN], cnt, vis[MAXN][110], dis[MAXN]; 14 15 struct Edge 16 { 17 int to, next, w; 18 }edge[MAXN * (MAXN - 1)]; 19 20 struct Node 21 { 22 int pot, num; 23 }node; 24 25 void add(int a, int b, int c) 26 { 27 cnt ++; 28 edge[cnt].to = b; 29 edge[cnt].w = c; 30 edge[cnt].next = head[a]; 31 head[a] = cnt; 32 } 33 34 void spfa() 35 { 36 queue<Node> Q; 37 node.pot = 1, node.num = 0; 38 dis[1] = 0; 39 vis[1][0] = 1; 40 Q.push(node); 41 while(!Q.empty()) 42 { 43 Node a = Q.front(); 44 Q.pop(); 45 vis[a.pot][a.num] = 0; 46 for(int i = head[a.pot]; i != -1; i = edge[i].next) 47 { 48 int to = edge[i].to; 49 int p = a.num; 50 if(to > n) 51 p ++; 52 if(dis[to] > dis[a.pot] + edge[i].w && p <= k) 53 { 54 dis[to] = dis[a.pot] + edge[i].w; 55 if(!vis[to][p]) 56 { 57 vis[to][p] = 1; 58 node.pot = to, node.num = p; 59 Q.push(node); 60 } 61 } 62 } 63 } 64 } 65 66 int main() 67 { 68 mem(head, -1), cnt = 0; 69 mem(vis, 0), mem(dis, inf); 70 scanf("%d%d%d%lld", &n, &m, &k, &r); 71 for(int i = 1; i <= n + m; i ++) 72 scanf("%lld%lld", &x[i], &y[i]); 73 for(int i = 1; i < n + m; i ++) 74 { 75 for(int j = i + 1; j <= n + m; j ++) 76 { 77 if((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]) <= r * r) 78 { 79 add(i, j, 1); 80 add(j, i, 1); 81 } 82 } 83 } 84 spfa(); 85 printf("%d\n", dis[2] - 1); 86 return 0; 87 } 88 89 /* 90 测试数据: 91 5 3 1 3 92 0 0 93 5 5 94 0 3 95 0 5 96 3 5 97 3 3 98 4 4 99 3 0 100 2 101 102 10 1 1 2 103 0 0 104 3 1 105 -2 0 106 -2 2 107 -2 4 108 -2 6 109 0 6 110 2 6 111 2 4 112 2 2 113 2 0 114 1 115 116 10 1 1 2 117 0 0 118 3 1 119 -2 0 120 -2 2 121 -2 4 122 -2 6 123 0 6 124 2 6 125 2 4 126 2 2 127 3 0 128 8 129 130 6 3 2 50000000 131 0 0 132 50000000 100000000 133 100000000 100000000 134 100000000 0 135 100000000 50000000 136 50000000 0 137 -100000000 50000000 138 0 50000000 139 0 100000000 140 2 141 */