CCF201403-4 無線網路(100分)
阿新 • • 發佈:2019-01-02
試題編號: | 201403-4 |
試題名稱: | 無線網路 |
時間限制: | 1.0s |
記憶體限制: | 256.0MB |
問題描述: |
問題描述
目前在一個很大的平面房間裡有 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 |
問題描述:(參見上文)。
問題分析:這是一個求最優問題,通常用BFS(廣度優先搜尋)來實現。據稱,該問題還可以用SPFA演算法來實現。程式說明:陣列visited[]用於標記訪問過的座標。函式bfs()的引數是為程式通用性而設定的,就本問題而言,可以使用常量。
網友指出,程式有錯,並且給出了錯誤的樣例。據此修改了程式,後一個程式才是正解。
CCF的線上評判系統中的測試資料常常不夠充分,程式有BUG照樣得100分。
後一個程式增加了增設路徑器的計數,如果已經用過2個,則以後不得再用增設路由器,這時只在已經設定好的路由器中搜索。參見程式中的17行的程式碼、50-53行的程式碼、以及70-73行的程式碼。
提交後得100分的C++語言程式如下(有BUG的100分):
/* CCF201403-4 無線網路 */
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int N = 100 + 100;
struct {
long long x, y;
} coord[N+1];
struct node {
long long x, y;
int step;
};
bool visited[N+1];
int bfs(int n, int begin, int end, long long r)
{
// 變數初始化
memset(visited, false, sizeof(visited));
// 設定根結點
node start, front, v;
start.x = coord[begin].x;
start.y = coord[begin].y;
start.step = 0;
queue<node> q;
q.push(start);
// 設定根結點為已經訪問過
visited[begin] = true;
while(!q.empty()) {
front = q.front();
q.pop();
// 到達終點則結束
if(front.x == coord[end].x && front.y == coord[end].y)
return front.step - 1;
// 搜尋可以連線的路由器
for(int i=0; i<n; i++) {
// 訪問過的座標則跳過
if(visited[i])
continue;
// 判定下一個路由器的座標是否在半徑r之內, 不在半徑之內則跳過,在半徑之內則繼續搜尋
if((front.x - coord[i].x) * (front.x - coord[i].x) + (front.y - coord[i].y) * (front.y - coord[i].y) > r * r)
continue;
else {
// 第i個路由器設為已經訪問過
visited[i] = true;
// 計算步數,並且將第i個路由器加入佇列
v.x = coord[i].x;
v.y = coord[i].y;
v.step = front.step + 1;
q.push(v);
}
}
}
return 0;
}
int main()
{
int n, m, k;
long long r;
// 輸入資料
cin >> n >> m >> k >> r;
for(int i=0; i<n+m; i++) // n個路由器的位置+可以增設的m個路由器的位置
cin >> coord[i].x >> coord[i].y;
// BFS
int ans = bfs(n + m, 0, 1, r);
// 輸出結果
cout << ans << endl;
return 0;
}
/*
測試資料:
5 3 1 3
0 0
5 5
0 3
0 5
3 5
3 3
4 4
3 0
2
10 1 1 2
0 0
3 1
-2 0
-2 2
-2 4
-2 6
0 6
2 6
2 4
2 2
2 0
1
10 1 1 2
0 0
3 1
-2 0
-2 2
-2 4
-2 6
0 6
2 6
2 4
2 2
3 0
8
6 3 2 50000000
0 0
50000000 100000000
100000000 100000000
100000000 0
100000000 50000000
50000000 0
-100000000 50000000
0 50000000
0 100000000
2
*/
提交後得100分的C++語言程式如下(正解):
/* CCF201403-4 無線網路 */
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 100 + 100;
struct {
long long x, y;
} coord[MAXN+1];
struct status {
long long x, y;
int step, kcount;
};
bool visited[MAXN+1];
int dfs(int n, int m, int k, int begin, int end, long long r)
{
int max;
// 變數初始化
memset(visited, false, sizeof(visited));
// 設定根結點
status start, front, v;
start.x = coord[begin].x;
start.y = coord[begin].y;
start.step = 0;
start.kcount = 0;
queue<status> q;
q.push(start);
// 設定根結點為已經訪問過
visited[begin] = true;
while(!q.empty()) {
front = q.front();
q.pop();
// 到達終點則結束
if(front.x == coord[end].x && front.y == coord[end].y)
return front.step - 1;
// 搜尋可以連線的路由器
if(front.kcount == k)
max = n;
else
max = n + m;
for(int i=0; i<max; i++) {
// 訪問過的座標則跳過
if(visited[i])
continue;
// 判定下一個路由器的座標是否在半徑r之內, 不在半徑之內則跳過,在半徑之內則繼續搜尋
if((front.x - coord[i].x) * (front.x - coord[i].x) + (front.y - coord[i].y) * (front.y - coord[i].y) > r * r)
continue;
else {
// 第i個路由器設為已經訪問過
visited[i] = true;
// 計算步數,並且將第i個路由器加入佇列
v.x = coord[i].x;
v.y = coord[i].y;
v.step = front.step + 1;
if(i >= n)
v.kcount = front.kcount + 1;
else
v.kcount = front.kcount;
q.push(v);
}
}
}
return 0;
}
int main()
{
int n, m, k;
long long r;
// 輸入資料
cin >> n >> m >> k >> r;
for(int i=0; i<n+m; i++) // n個路由器的位置+可以增設的m個路由器的位置
cin >> coord[i].x >> coord[i].y;
// BFS
int ans = dfs(n, m, k, 0, 1, r);
// 輸出結果
cout << ans << endl;
return 0;
}
/*
測試資料:
5 3 1 3
0 0
5 5
0 3
0 5
3 5
3 3
4 4
3 0
2
10 1 1 2
0 0
3 1
-2 0
-2 2
-2 4
-2 6
0 6
2 6
2 4
2 2
2 0
1
10 1 1 2
0 0
3 1
-2 0
-2 2
-2 4
-2 6
0 6
2 6
2 4
2 2
3 0
8
6 3 2 50000000
0 0
50000000 100000000
100000000 100000000
100000000 0
100000000 50000000
50000000 0
-100000000 50000000
0 50000000
0 100000000
2
*/