POJ 2376 :Cleaning Shifts(贪心)

原题地址:点击打开链接

题意:

给定N个小区间[Si, Ei],求能用它们覆盖区间[1,T]的最小组合。


数据范围:

1 <= N <= 25000

1 <= T <= 10^6


输入:

第一行: N T

第2到第N+1行: 区间起点Si 区间终点Ei


输出:

一行:最少区间数,如果不能覆盖输出-1


例子:


输入:

3 10

1 7

3 6

6 10


输出:

2

这个题我自己没做出来,不知道为什么总是Wrong Answer,日后回头再看,暂且传上大神的思路和代码:(原文传送地址:点击打开链接

贪心策略是从左往右,尽量选择长度最大的区间。

首先对所有奶牛排序,按照开始时间排序。

然后更新起点=终点+1,搜索剩下的奶牛中能够覆盖这个起点同时终点最远的那一头,更新终点。

#include <iostream>
#include <algorithm>
using namespace std;
int N, T;
 
struct Cow
{
	int begin;	// 开始时间 
	int end;	// 结束时间 
};
 
#define MAX_COWS 25000
Cow cow[MAX_COWS];
 
bool is_greater(const Cow& a, const Cow& b)
{
	return a.begin < b.begin || (a.begin == b.begin && a.end > b.end);
}
 
int solve()
{
	int used_cows = 0;
	int end = 0;
	int index = 0;
	while(end < T)
	{
		int begin = end + 1;
		// 寻找一头既能从begin干起,又能一直干到最远的牛 
		for (int i = index; i < N; ++i)
		{
			if (cow[i].begin <= begin)
			{
				// 能够覆盖起始点 
				if (cow[i].end >= begin)
				{
					// 将终点延长到最远 
					end = max(end, cow[i].end);
				}
			}
			else
			{
				// 不能覆盖起始点,说明上一头牛的终点就是最远点,需要换一头牛了 
				index = i;
				break;
			}
		}
 
		// 没找到这样的牛,这个case失败 
		if (begin > end)
		{
			return -1;
		}
		else
		{
			++used_cows;
		}
	}
 
	return used_cows;
}
 
///SubMain//
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
	cin >> N >> T;
	for (int i = 0; i < N; ++i)
	{
		cin >> cow[i].begin >> cow[i].end;
	}
	sort(cow, cow + N, is_greater);
	cout << solve() << endl;
#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    system("out.txt");
#endif
    return 0;
}
///End Sub//


我的思路和大神的感觉是差不多,就是不断选取 剩下的中、可选的离已经覆盖的区间最远的一个。就是不知道漏了什么。
我的代码(提交Wrong Answer):

#include <iostream>
#include <algorithm>
#define MAX_N 25000

using namespace std;

int N, T;

//保存N个区间,并用于排序 
pair<int, int> itv[MAX_N];

//排序的比较 
bool compare(const pair<int, int> &a, const pair<int, int> &b)
{
	if(a.first == b.first)
		return a.second < b.second;
	return a.first < b.first;
}

void solve()
{
	//按区间起点排序 
	sort(itv, itv + N, compare);
	
	int ans = 0;
	int end = 0;	//当前覆盖的区间[1, end] 
	int i = 0;
	
	while(end < T){

		//查找可选区间中最右的
		int t = end + 1;
		while(i < N){
			if(itv[i].first <= t){
				if(itv[i].second >= t)
					end = max(end, itv[i].second);
			}
			else
				break;
			i ++;
		}
		
		//找到了可选区间
		if(end > t)
			ans ++;

		//找不到可选区间
		else{
			cout << "-1" << endl;
			return;
		}
	}
	
	cout << ans << endl;
}

int main()
{
	while(cin >> N >> T){
		for(int i = 0; i < N; i ++)
			cin >> itv[i].first >> itv[i].second;
		solve();
	}
	return 0;
}
不知道错在哪了,主要是测试数据太少了。。不过还是学到了一些东西,现在总结一下:

pair模板的使用:

定义:pair < type, type> name;

访问第一个元素: name.first, 访问第二个元素:name.second

排序:如果对pair类型排序,第一个元素的值优先

详细解释:点击打开链接

sort函数可以加第三个参数,用于比较方式:点击打开链接

最后最重要重要的:

贪心的核心思想:不断选取当前最优解,但解法需要自己证明是否正确,用贪心解决问题是非常高效的,麻烦的就是不知道自己的策略 是不是正确的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值