uva10020 - Minimal coverage(区间覆盖)

题目:uva10020 - Minimal coverage(区间覆盖)


题目大意:给出一些线段,然后问怎样取能使得最少的线段覆盖区间[0, M].


解题思路:先预处理掉那些和区间【0,M】不沾边的线段。

                 将线段按照起点小的排序。 

                 接着遍历这些线段。首先先判断起点最小的点是否<=0,如果不满足这个说明它不能覆盖区间。

                 然后每次都小于等于当前覆盖的起点的最长线段,之后要将起点更新成这个最长线段的终点。然后接着判断下一条线段。如果更新了起点发现依然找不到满足条件的线段,说明不能覆盖。

                 最后还要看一下是否能够覆盖到M。


代码:

#include 
#include 
#include 
using namespace std;

const int N = 100005;
int m, n;
int visit[N];

struct segments {

	int l, r;
}s[N];

int cmp (const segments& a, const segments &b) { return a.l < b.l; }

int Max (const int a, const int b) {return a > b ? a: b;}

int solve () {

	memset (visit, 0, sizeof (visit));
	if (s[0].l > 0)             //判断能否覆盖区间起点
		return 0;
	int st = 0;
	int ll = -1;
	int t = -1;
	for (int i = 0; i < n; i++) {

		if (s[i].l <= st) {  //找符合条件的最长的线段

			if (ll < s[i].r) {

				visit[i] = 1;
				if (t >= 0)
					visit[t] = 0;
				t = i;
				ll = Max (ll, s[i].r);
			}
		} else {           

			if (st == ll)  //更新后发现依然没有
				return 0;
			st = ll;       //更新起点

			i--;
			t = -1;        //更新起点后这个记录之前记录的线段就是确定需要,和更新后的没有关联了   
		}
		if (ll >= m)           //能否覆盖终点
			break;
	}
	if (ll < m)                    //能否覆盖终点

		return 0;
	int count = 0;
	for (int i = 0; i < n; i++)
		if (visit[i])
			count++;
	return count;
}

int main () {

	int t;
	int l, r;
	scanf ("%d", &t);
	while (t--) {

		scanf ("%d", &m);
		n = 0;
		while (scanf ("%d%d", &l, &r), l || r) {

			if (r <= 0 || l >= m)
				continue;
			s[n].l = l;
			s[n].r = r;
			n++;
		}

		sort (s, s + n, cmp);
		int count = solve();
		printf ("%d\n", count);
		if (count) {
			for (int i = 0; i < n; i++)
				if (visit[i])
					printf ("%d %d\n", s[i].l, s[i].r);
		}
		if (t)
			printf ("\n");
	}
	return 0;
}


你可能感兴趣的:(UVA,算法设计)