贪心与sort的妙用(洛谷p2240,洛谷p1223,洛谷p1803)

鼠鼠在写了几道题之后发现,这几道题类似,所以就想放一块一起总结一下,用的思想就是所谓的“贪心”,就是局部最优->总体最优,但我感觉这个概念其实比较抽象,所以直接看题。。

洛谷p2240:部分背包问题(洛谷p2240)-优快云博客

这个讲过了,有需要的同学可以去看下。

洛谷p1223:P1223 排队接水 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这个题的思路就是,先让时间短的先接水,时间长的后接,自然而然的就得到了较短的平均时间,因为耗着时间越长的越后,他加的次数便越少,不知道有没有同学和我刚开始一样没搞清楚一个概念,他等待的时间=第一个人耗费的时间+第二个人耗费的时间+.......+他前一个人消耗的时间。所以接水时间长的要把它放到最后,那如何很方便的将他们都排序呢?

        很简单,创建一个数组(当一维数组装不下需要的数据时,我们便可以考虑封装结构体),然后直接sort(真好用)

代码:

#include<iostream>
#include<algorithm>
using namespace std;
struct people {
	int ID;
	long long time;
};
people a[1000];
bool cmp(people p1, people p2) {
	return p1.time < p2.time;
}
long long ti[1000];
int main() {
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		a[i].ID = i + 1;
		cin >> a[i].time;
	}
	sort(a, a + n, cmp);
	long long stime = 0;
	long long sumtime=0;
	for (int i = 0; i < n; i++)
	{
		cout << a[i].ID<<" ";
		stime += a[i].time;
		ti[i] = stime;
		sumtime += ti[i];
	}
	sumtime -= ti[n - 1];
	cout << "\n";

	printf("%.2f", 1.0 * sumtime / n);
	return 0;
}

注意一点,记得开long long,int不够,然后你如果float a=b/c;b和c是long long的话,例如b=5,c=2,a并不会等于2.5000000,而是2.0000000,因为他会除完之后先把末尾舍去,在赋给a,那我们可以采用float a=1.0*b/c这个办法解决。

洛谷p1803:P1803 凌乱的yyy / 线段覆盖 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这个题和上面两道思路区别不大,但我认为难想的一点在于找到最优解的过程没有前两道那么简单明了。

        如果所有比赛都没有冲突,那么就可以全部参赛,那如果有两个比赛有冲突了(两种情况):1.一个包含另一个,那么选哪个?结束的早的,方便我参加下一个比赛;2.时间上有重叠,同理,选择结束的早的,原因同上。递推下去,那意思就是说我只要每次都选择,结束的早的,永远对我最有利,有点类似于数学归纳法。

        那我们思路一样,用一个结构体封装起来,创一个数组,那按什么排序(sort)呢?结束早的排前边,然后创建一个整形记录此时的时刻,每进行完一个活动,看接下来的活动开始了没,开始了就下一个,没开始就参加

#include<iostream>
#include<algorithm>
using namespace std;
struct activity {
	int start;
	int end;
};
bool cmp(activity a1, activity a2) {
	return a1.end <= a2.end;
}
activity a[1000000];
int main() {
	int n;
	int ans = 0,finish=0;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> a[i].start >> a[i].end;
	}
	sort(a, a + n, cmp);
	for (int i = 0; i < n; i++) {
		if (finish <= a[i].start) {
			ans++;
			finish = a[i].end;
		}
	}
	cout << ans;
	return 0;
}

如果有帮助还请点个赞,有问题的话可以评论捏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值