Acwing734(贪心+01背包)

题目链接:https://www.acwing.com/problem/content/736/

解题思路:
首先我们假定一个序列:a1, a2, a3, …, an这个序列就是最终的序列,其中最终的序列中可能会有贡献为0的点,所有即使把贡献为0的点抽出去,也不会造成任何影响,并且此时对于ai, aj(i < j)来说,如果将其调换位置则造成的贡献相对于原来的顺序来说一定小于或者等于0。
根据这个性质我们可以得到一个不等式:
假设目前的时间为t,则有:
ei + ej - t * li - (t + si) * lj >= ei + ej - t * lj - (t + sj) * li。
对着个不等式进行化简可以得到如下:
si / li <= sj / lj。(神奇,简化后发现和e没有关系了)

贴上代码一份:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int maxn = 105, M = 10005;

struct Node {
	double cal;
	int s, e, l;
}node[maxn];

int T, n, m;
int f[maxn][M];

inline bool cmp(Node a, Node b) {
	return a.cal < b.cal;
}

int main(void) {
//	freopen("in.txt", "r", stdin); 
	scanf("%d", &T);
	int count = 1;
	while(T --) {
		m = 0;
		scanf("%d", &n);
		for(int i = 1; i <= n; i ++) {
			int &a = node[i].s;
			int &b = node[i].e;
			int &c = node[i].l;
			double &d = node[i].cal;
			scanf("%d%d%d", &a, &b, &c);
			if(c == 0) d = 1000000;
			else d = a * 1.0 / c;
			m += a;
		//	printf("%d %d %d\n", node[i].s, node[i].e, node[i].l);
		}
		
		sort(node + 1, node + 1 + n, cmp);
		
		//for(int i = 1; i <= n; i ++)
		//	printf("%d %d\n", node[i].e, node[i].s);
		
		memset(f, -1, sizeof f);
		for(int j = 0; j <= m; j ++) f[0][j] = 0;
		for(int i = 0; i <= n; i ++) f[i][0] = 0;
		for(int i = 1; i <= n; i ++)
			for(int j = 1; j <= m; j ++) {
				//不选
				f[i][j] = f[i - 1][j];
				//选择 
				if(j >= node[i].s) 
					f[i][j] = max(f[i][j], f[i - 1][j - node[i].s] + max(0, node[i].e - (j - node[i].s) * node[i].l));
			//	printf("%d %d\n", f[0][0], f[i][j]); 
			}
		
		int fi = 0;
		for(int i = 1; i <= n; i ++)
			for(int j = 1; j <= m; j ++)
				fi = max(fi, f[i][j]);
		printf("Case #%d: %d\n", count ++, fi);
	} 

	return 0;
}

总结:对于DP这样字的题目,时常和贪心结合在一起。自己被坑了的地方:f[0][0]没有进行初始化,在这里花了很多的时间,下次一定要好好的堆自己的代码进行检查,尤其是对于初始化的部分。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
01背包问题是指有n个物品和一个容量为V的背包,每种物品只有一个,可以选择放或不放,要求在不超过背包容量的前提下,尽可能多地装入物品。贪心算法可以用来解决一部分01背包问题,即每个物品只能选择全部装入或不装入的情况。 具体的贪心策略是按照物品单位重量的价值从大到小的顺序,依次将物品装入背包中,直到背包无法再装下为止。这种贪心策略称为单位重量价值排序策略。 下面是一个简单的实现示例: ```python def knapsack_01(weights, values, capacity): n = len(weights) # 计算每个物品的单位重量价值 vpw = [(values[i] / weights[i], weights[i], values[i]) for i in range(n)] # 按照单位重量价值从大到小排序 vpw.sort(reverse=True) # 背包当前剩余容量 remain = capacity # 装入背包的总价值 total_value = 0 # 依次将单位重量价值最大的物品装入背包中 for i in range(n): if remain >= vpw[i][1]: remain -= vpw[i][1] total_value += vpw[i][2] else: total_value += remain * vpw[i][0] break return total_value ``` 其中,weights和values分别为n个物品的重量和价值,capacity为背包容量。vpw是一个列表,其中每个元素都是一个三元组,分别表示物品的单位重量价值、重量和价值。在实现中,我们将vpw按照单位重量价值从大到小排序,然后依次将单位重量价值最大的物品装入背包中,直到背包无法再装下为止。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值