1. 程式人生 > >POJ 1328 貪心+降維

POJ 1328 貪心+降維

題意分析:

     給定一個直角座標系,定義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;
}