P1094 [NOIP2007 普及组] 纪念品分组

[NOIP2007 普及组] 纪念品分组

题目背景

NOIP2007 普及组 T2

题目描述

元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得 的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品, 并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。

你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。

输入格式

共 $n+2$ 行:

第一行包括一个整数 $w$,为每组纪念品价格之和的上限。

第二行为一个整数 $n$,表示购来的纪念品的总件数 $G$。

第 $3\sim n+2$ 行每行包含一个正整数 $P_i$ 表示所对应纪念品的价格。

输出格式

一个整数,即最少的分组数目。

样例 #1

样例输入 #1

100 
9 
90 
20 
20 
30 
50 
60 
70 
80 
90

样例输出 #1

6

提示

$50%$ 的数据满足:$1\le n\le15$。

$100%$ 的数据满足:$1\le n\le3\times10^4$,$80\le w\le200$,$5 \le P_i \le w$。


贪心

重在证明,虽然AC了证明还是模糊

贪心策略:

1.首先对所有物品的价值从小到大进行排序

2.用两个指针,一个指向前端,另一个指向后端;

3.最小的匹配最大的时候分组数最小

4.当 $a_i + a_j > w$时,j--;

说明后面数太大了,只能独立作为一个组

5.当 $a_i + a_j <= w$ 时,i++, j--;

两个数作为一个组

证明:

分情况进行讨论:

首先贪心得到的解是一种可行方案,而最后的最优解是所有可行方案中的最小值,
因此可以证明出 最优解 <= 贪心得到的解

存在最优解S ,他不是按照贪心步骤得到的;

1.$a_i + a_j > w$ 时,由于从小到大进行了排序 $a_i$ 是当前最小的,说明$a_j$不能与其他任何$a_k$为一组,$i < k < j $,因此$a_j$只能独立分组;

2.$a_i + a_j <= w$ ,而最优解中并不是$a_i与a_j$ 一组;

(1)$a_j$ 是独立分组的,并且$a_i$也是独立分组的时候,由于$a_i + a_j <= w$,将它俩合并为同一个组,这时分组数-1,这里可以证明出最优解 >= 贪心得到的解

到这一步我们可知贪心得到的解就是最优解。

进一步说明:
已知 $i < k < j$,

(2)$a_j$ 单独一组,$a_i 与 a_k$ 一组,将$a_i$与$a_k4拆分,再把$a_i$与$a_j$合并,这是分组数不变

(3)$a_j与a_k$ 一组,$a_i$单独一个组,这时候交换$a_i,a_k$, 分组数仍不变

C++ 代码

#include <bits/stdc++.h>
using namespace std;

const int N = 3e4 + 10;

int w,n;
int a[N];
int ans;

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	cin >> w >> n;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
	}
	sort(a + 1, a + 1 + n);
	int i = 1,j = n;
	while(i <= j){
		if(a[i] + a[j] > w) {
			ans ++;   //单独作为一个组
			j--; 
		}
		else{
			ans ++;  //两件物品一起作为一个组
			i++;
			j--; 
		}
	}
	cout << ans << endl;
	return 0;
}

posted @   LTphy  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示