POJ 1328 貪心+降維
阿新 • • 發佈:2018-12-09
題意分析:
給定一個直角座標系,定義x軸為海岸線,海岸線上方是海,下方是陸地.
在海域零星分佈一些海島, 需要要在海岸線上安裝若干個雷達覆蓋這些海島,
每個雷達的覆蓋半徑都是相同且固定的.
現在給定所有海島的座標(x,y), 以及雷達的覆蓋半徑d,
問可以覆蓋所有海島的最小雷達數.
?錯誤?思路:
每個雷達畫圓。從三點定圓的思路找:先找出相同x座標下的y-max,隨後對於每個y-max按照從左往右的順序找出滿足要求的最遠的雷達位置。但是,由於沒有考慮到兩個雷達之間的銜接以及y-max點不一定在圓的邊界,導致錯誤。
正確思路:
每個點畫圓。然後在x軸上有交點(如果沒有代表不存在解)。每一個截距區間為能夠探測到島的雷達的範圍;然後找儘可能多的重複;由此,將x-y座標變成x-區間問題。
轉化為-->如何找到儘可能少的點,使得每一個獨立區間內都有一個點。
方法:如果兩個區間有重合,選擇重合的小區間作為點出現的可能區間;如果沒有重合,則重新選擇一個新的點。
從左往右開始查詢,那麼把點出現區間的最右端作為點的真實位置;如果有重合,點數量不增加,但是位置可能發生改變(在重合區間的最右端);如果不重合,點數量增加,位置也改變。
錯誤分析:
if (intervals[i].left <= pos) pos = min(intervals[i].right, pos);//internal or others else { ++ans; pos = intervals[i].right; }
這裡min應該取pos(原來的點位置),而不是intervals[i-1].right
double r; const double r_2 = d*d; for (int i = 0; i < n; ++i) { cin >> x >> y; if (y > d) { ans = false; } r = sqrt(r_2 - y * y);
好幾處的double轉換應該注意。不然會錯誤。
標準程式碼:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
int n, d;
struct interval
{
double left, right;
} intervals[1005];
bool cmp(interval a, interval b)
{
return a.left <= b.left;// have to be
}
void print(){
cout << '\n';
for(int i = 0 ; i < n; ++i){
cout << intervals[i].left << ' ' << intervals[i].right << '\n';
}
cout << '\n';
}
int f()
{
sort(intervals, intervals + n, cmp);
// print();
int ans = 1;
double pos = intervals[0].right;
for (int i = 1; i < n; ++i)
{
if (intervals[i].left <= pos)
pos = min(intervals[i].right, pos);//internal or others
else
{
++ans;
pos = intervals[i].right;
}
}
return ans;
}
int main()
{
int cnt = 0;
while (1)
{
cin >> n >> d;
if (n == 0 || d == 0)
break;
bool ans = true;
int x, y;
double r;
const double r_2 = d*d;
for (int i = 0; i < n; ++i)
{
cin >> x >> y;
if (y > d)
{
ans = false;
}
r = sqrt(r_2 - y * y);
intervals[i].left = x - r;
intervals[i].right = x + r;
}
cnt++;
cout << "Case " << cnt << ": " << (ans ? f() : -1) << '\n' ;
}
return 0;
}