1. 程式人生 > >貪心演算法-----區間覆蓋問題

貪心演算法-----區間覆蓋問題

(一)點覆蓋區間(雷達/灌溉噴頭)

題目描述:假設海岸線是一條無限延伸的直線。陸地在海岸線的一側,而海洋在另一側。每一個小的島嶼是海洋上的一個點。雷達坐落於海岸線上,只能覆蓋d距離,所以如果小島能夠被覆蓋到的話,它們之間的距離最多為d。題目要求計算出能夠覆蓋給出的所有島嶼的最少雷達數目。對於每個小島,我們可以計算出一個雷達所在位置的區間。

演算法實現:

//2018年6月11日與遼寧瀋陽東北大學

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;

struct Qujian
{
	double start, end;

};

int radarNum = 1;


//這個函式寫法值得學習

/************************************************************/
int cmp(const void *a, const void *b)
{
	return (*(Qujian *)a).start>(*(Qujian *)b).start ? 1 : -1;
}
/**********************************************************/
int main(void)
{
	double x, y;
	cout << "請輸入島嶼數目和雷達最大探測距離  ";
	int num_island; double DisMax;

	cin >> num_island >> DisMax;
	Qujian qujian[50];

	for (int i = 0; i < num_island; ++i)
	{
		cout << "請輸入第"<<i+1<<"個島嶼的橫縱座標: "<<endl;
		cin >> x >> y;

		if (y > DisMax)
		{
			cout << " 這個島嶼檢測不到" << endl;
			exit(-1);
		}

		qujian[i].start = x - sqrt(DisMax*DisMax -y*y);
		qujian[i].end = x +sqrt(DisMax*DisMax - y*y);
	}

	qsort(qujian, num_island, sizeof(qujian[0]), cmp);

	for (int j = 1; j <= num_island; ++j)
	{
		if (qujian[j].start >= qujian[0].start&&qujian[j].end <= qujian[0].end)
		{
			qujian[0].end = qujian[j].end;
		}

		if (qujian[j].start > qujian[0].end)
		{
			//qujian[0].start = qujian[j].start;

			qujian[0].end = qujian[j].end;
			radarNum++;
		}
	}

	cout << "需要雷達總數是:" << radarNum << endl;

	return 0;

}

問題轉化為如何用盡可能少的點覆蓋這些區間。先將所有區間按照左端點大小排序,初始時需要一個點。如果兩個區間相交而不重合,我們什麼都不需要做;如果一個區間完全包含於另外一個區間,我們需要更新區間的右端點;如果兩個區間不相交,我們需要增加點並更新右端點。

草圖:

(二)線段覆蓋區間

//2018年6月11日於遼寧瀋陽
//Author:Mr Yang

//(二)線段覆蓋區間
//
//題目描述:
//
//用i來表示x座標軸上座標為[i - 1,i]的長度為1的區間,並給出n(1≤M≤200)個不同的整數,表示n個這樣的區間。
//現在要求畫m條線段覆蓋住所有的區間,
//條件是:每條線段可以任意長,但是要求所畫線段的長度之和最小,並且線段的數目不超過N(1≤N≤50)。
//輸入:
//輸入包括多組資料,每組資料的第一行表示點數n和所需線段數m,後面的n行表示點的座標
//輸出:

//輸出每組按規定線段條數被覆蓋的線段的最短總長度。


//示例輸入:
//5 3
//1 3 5 8 11

//示例輸出:
//7
//演算法思想:
//第一步將所有區間間距排序,再連線間距最短的兩個線段(間距大小並列的只連線一個),統計這時候有多少條線段,如果大於限制線段樹就繼續連線區間間距次小的兩個區間......直到線段數目等於規定最大線段數為止

//演算法實現:

#include <iostream>
#include <algorithm>
#include <cmath>

#define N 200

using namespace std;

struct Qujian
{
    int start, end;
};

Qujian qujian[200];     //存放輸入區間

//int cmp(const int&a, const int&b)
//{
    //return (*(Qujian *)a).start>(*(Qujian *)b).start ? 1 : -1;
//    return a
//}
int main()
{
    int PointNum, segmentLimit;
    cout << "請輸入區間數目和線段限制最大數:" << endl;
    cin >> PointNum >> segmentLimit;

    cout << "請輸入具體區間: " << endl;
    int buf_Point;
    for (int j = 0; j <PointNum; ++j)    
    {
        
        cin >> buf_Point;

        qujian[j].start = buf_Point - 1;
        qujian[j].end = buf_Point;
        
    }

    int Distance[N] = {-1};   //Distance[N]存相鄰區間的距離
    for (int j = 0; j < PointNum-1; j++)
    {
        Distance[j] = qujian[j + 1].start - qujian[j].end;

    }

    //qsort(Distance, PointNum - 1, sizeof(Distance[0]), cmp);
    sort(Distance, Distance + PointNum - 1);
    //cout << Distance[0] << Distance[1] << Distance[2] << Distance[3]<< endl;看看排序拍的對不

    int ResLength = 0; int SegmentNum = PointNum;
    for (int j = 0; j < PointNum - 1; ++j)
    {
        if (Distance[j] > 0&&j==0)
        {
            ResLength = Distance[j] + 2;
            SegmentNum--;

            if (SegmentNum == segmentLimit)
            {
                ResLength += (PointNum - j - 2);//ResLength=ResLength+(PointNum-1-(j+1)
                break;
            }
        }
        else if (Distance[j] > 0 && j > 0)
        {
            ResLength = ResLength+ Distance[j] + 1;
            SegmentNum--;

            if (SegmentNum == segmentLimit)
            {
                ResLength+=(PointNum - j - 2);
                break;
            }
        }
    }

    cout << ResLength << endl;
    return 0;

}

參考:https://blog.csdn.net/cordova/article/details/50853147

轉載必須註明出處