1. 程式人生 > 實用技巧 >POJ3069 -- Saruman's Army

POJ3069 -- Saruman's Army

題意:
直線上有N個點。 點i的位置是Xi。從這N個點中選擇若干個,給它們加上標記。 對每一個點,其距離為R以內的區域裡必須有帶有標記的點(自己本身帶有標記的點, 可以認為與其距離為 0 的地方有一個帶有標記的點)。 在滿足這個條件的情況下, 希望能為儘可能少的點新增標記。 請問至少要有多少點被加上標記?
Ps:多組輸入,直到N / R = -1時候結束

輸入
0 3
10 20 20
10 7
70 30 1 7 15 20 50
-1 -1

輸出
2
4

原題連結戳這!!!

解析:區間型別的貪心題。開始將最左邊的點設為未被覆蓋的點bg,向右尋找至第一個小於或等於bg + R的點,此時可以將該點標記為p,接著p其實也覆蓋了p + R,那找到第一個大於p + R的點作為下一個最左邊未被覆蓋的點,依次下去。下面大概草草的畫了一個圖作為理解。

AC程式碼:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long LL;
const int num = 1005;
int r, n, p, res;
int a[num];

int main()
{
	ios::sync_with_stdio(false);
	while(cin >> r >> n && (r != -1 || n != -1))
	{
		memset(a, 0, sizeof(a));
		res = 0, p = 0;
		for(int i = 1; i <= n; i++)
			cin >> a[i];
		sort(a + 1, a + n + 1);
		int i = 1; //此時運動到第i個點 
		while(i <= n)
		{
			int bg = a[i]; //表示當前未覆蓋的最左邊位置
			for(int j = i + 1; ; j++) //找到bg最右邊且小於r的點進行標記 
			{
				if(a[j] - bg > r)
				{
					p = a[j-1]; //將標記點記錄
					i = j; //更新當前位置 
					res++; //標記點數量增加 
					break;	
				}
			}
			for(int j = i; ; j++) //標記點還能覆蓋其右邊小於r的位置 
			{
				if(a[j] - p > r) //當該點大於r時, 重新作為當前未覆蓋的最左邊位置 
				{
					i = j; //更新當前位置 
					break;
				}
			}
		}
		cout << res << endl;
	}
	return 0;
}