(水)POJ-3262 贪心,背包,比率问题

题目大意:

有n个牛在FJ的花园乱吃。

所以FJ要赶他们回牛棚。

每个牛在被赶走之前每秒吃Di个花朵。赶它回去FJ要花的时间是Ti,走回来再赶其他牛也需要Ti的时间。在被赶走的过程中牛就不能乱吃了

题目链接:点击打开链接

分析:这个题与贪心中的背包问题很像,都涉及到比率问题,按照比率来排序。背包问题中以 价值/质量 来从大到小排序,而这里我们以 D/T 来从大到小排序,以此顺序来赶牛就行了。

下面给出证明:

设di,ti,Ti分别代表编号为i(以 di / ti 从大到小依次编号)的牛每秒吃di个花朵,赶它花的时间是ti,经过Ti时间才被赶走,我们先来考虑牛1

对牛1有 d1 / t1 > dk / tk(1<k<=n),即 d1 * tk > dk * t1

①按照上面的贪心思想,则牛1肯定最先被赶走。则此时的总花费为:

d1*T1+d2*T2.......+dn*Tn = d2*T2.......+dn*Tn    因为T1=0

②若不先赶牛1,那么我们交换牛1与牛i的顺序。则此时的总花费发生了变化

1.对于牛i后面的牛,其T不变

2.对于牛1,T1‘ = T1+t2+t3.....+ti = t2+t3.....+ti

3.对于牛i ,Ti‘ = 0

4.对于编号在1到i之间的牛,Tk‘ = Tk+ ( ti - t1 )

所以此时的总花费为:

d1*T1‘+d2*T2‘...+dn*Tn‘ = (d2*T2.......+dn*Tn)
+ (d1*t2+d1*t3...+d1*ti) + (d2*ti+d3*ti...+di-1*ti) - (d2*t1+d3*t1...+di-1*t1)

由于 d1 * tk > dk * t1,所以 (d1*t2+d1*t3...+d1*ti-1)-(d2*t1+d3*t1...+di-1*t1)>0

所以花费2 > 花费1

以此归纳,可知这种贪心方法是正确的。

附上代码:

#include<iostream>
#include<algorithm>
using namespace std;
struct Cow{ int t, d; Cow(int a = 0, int b = 0){ t = a, d = b; } }cow[100000 + 5];
long long ans, sum;
int n;
bool cmp(Cow &a, Cow &b){ return a.d * b.t > b.d * a.t; }  //为了避免除法产生小数而引起精度误差,我们采用相乘的形式
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d%d", &cow[i].t, &cow[i].d);
	sort(cow + 1, cow + n + 1, cmp);
	for (int i = 1; i <= n; i++)
	{
		sum += cow[i - 1].t * 2;        //来回一共2倍t
		ans += sum * cow[i].d;
	}
	printf("%lld\n", ans);
	return 0;
}
时间: 2024-11-08 21:18:52

(水)POJ-3262 贪心,背包,比率问题的相关文章

POJ 3624 01背包

初学DP,用贪心的思想想解题,可是想了一个多小时还是想不出. //在max中的两个参数f[k], 和f[k-weight[i]]+value[i]都是表示在背包容量为k时的最大价值 //f[k]是这个意思,就不用说了. //而f[k-weight[i]]+value[i]也表示背包容量为k时的最大价值是为什么呢? //首先,f[k-weight[i]]表示的是背包容量为k-weight[i]的容量,也就是说f[k-weight[i]] //表示的是容量还差weiht[i]才到k的价值,+walu

POJ 1384 Piggy-Bank 背包DP

所谓的完全背包,就是说物品没有限制数量的. 怎么起个这么intimidating(吓人)的名字? 其实和一般01背包没多少区别,不过数量可以无穷大,那么就可以利用一个物品累加到总容量结尾就可以了. 本题要求装满的,故此增加个限制就可以了. #include <stdio.h> #include <stdlib.h> #include <string.h> inline int min(int a, int b) { return a < b? a : b; } c

poj 2184 0---1背包的变形

这题是0--1背包的变形,对理解0--1背包有很大的帮组 题意:要选一些牛去参见展览,每个牛有幽默.智慧两个选择标准,要求选的这些牛使得幽默和智慧的总和最大且幽默和智慧的每个总和都必须是大于等于0: 刚看的这个题目是时候,知道是一个0--1背包的的题目,但就是不知道怎么来写出状态转移方程,因为题中的两个变量都是有负值的. 看了大牛的解题报告才知道. 我们可以把幽默个变量看成是体积 , 智慧看成是价值. 我们可以把每个牛幽默的值 , 放在一个坐标上,让后整体往右移,使得最小值为 0 , 那么这时候

POJ 1014 Dividing 背包

这道题使用多重背包,不过其实我也不太明白为什么叫这个名字. 因为感觉不是什么多重,而是物体的分解问题. 就是比如一个物体有数量限制,比如是13,那么就需要把这个物体分解为1, 2, 4, 6 如果这个物体有数量为25,那么就分解为1, 2, 4, 8, 10 看出规律吗,就是分成2的倍数加上位数,比如6 = 13 - 1 - 2 - 4, 10 = 25 - 1 - 2 - 4 - 8,呵呵,为什么这么分解? 因为这样分解之后就可以组合成所有1到13的数,为25的时候可以组合成所有1到25的数啦

POJ 3262 Protecting the Flowers 题解 《挑战程序设计竞赛》

题目:POJ - 3262 这道题,需要好好总结. 原来的思路是,依次计算出送走奶牛1~N会毁掉的花的数量,找出最小的,送走这头牛.然后又在剩下的奶牛中找可以使毁掉的花的数量最小的送走.如此循环直到全被送走. 对是对,只是也太繁琐了些,并且超时. 没有意识到其实这样的思路进行了很多次重复的比较. 后来看了别人的思路,发现可以先排序,一次就可以排好奶牛应该被送走的顺序. 刚开始觉得,这样很像之前做的Yogurt Factory题目,用动态规划记录每相邻两个牛的比较结果. 写完后发现不对,才发现又陷

POJ 2231 贪心吗?怎么感觉像是数学。。。。

过了两次用了两种不同方法,其实也差不多,如果真的暴力去求得话铁定超时,(好像优化减去一些不可能的情况也能过,但是我没尝试)所以找一下规律咯,没学过算法的渣只能靠思维做题了... #include<stdio.h> int a[10009]; int main() { int n,m,t,i,j; long long sum; while(scanf("%d",&n)!=EOF) { sum=0; for(i=1;i<=n;i++) scanf("%d

poj 1837 01背包

Balance Time Limit: 1000 MS Memory Limit: 30000 KB 64-bit integer IO format: %I64d , %I64u Java class name: Main [Submit] [Status] [Discuss] Description Gigel has a strange "balance" and he wants to poise it. Actually, the device is different fr

poj 1017(贪心)

[题目大意] 题目大意是这样的:某工厂生产几种产品,首先用packet包住,这些产品的高度都是h,底面积有1*1,2*2,3*3,4*4,5*5,6*6六种规格,下面我们要用高度为h,底面积为6*6的集装箱装这些货物,问怎样使所用集装箱数目最少? [解题思路] 我们首先必须先装底面积大的货物,并且对于面积为4*4,5*5,6*6的货物,每一件都需要一个独立的集装箱.对于底面积为3*3的货物,每四个需要一个集装箱. 那么我们可以得知对于装了底面积为3*3的货物的集装箱,其剩余可以装5,3,1个底面

【bzoj4922】[Lydsy六月月赛]Karp-de-Chant Number 贪心+背包dp

题目描述 给出 $n$ 个括号序列,从中选出任意个并将它们按照任意顺序连接起来,求以这种方式得到匹配括号序列的最大长度. 输入 第一行包含一个正整数n(1<=n<=300),表示括号序列的个数. 接下来n行,每行一个长度在[1,300]之间的括号序列,仅由小括号构成. 输出 输出一行一个整数,即最大长度,注意你可以一个序列也不选,此时长度为0. 样例输入 3 ()) ((() )() 样例输出 10 题解 贪心+背包dp 首先对于一个括号序列,有用的只有:长度.消耗'('的数目.以及'('减去

Charlie&#39;s Change POJ - 1787 (完全背包+记录路径)

完全背包输出路径:对于每一次更新记录一下路径:注意钱币个数: dp[i][0]代表在空间为i时需要多少枚钱币 dp[i][1]用来记录路径 cheek[j]用来记录在j时用了多少i枚钱币 思路在代码中: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define mem(a,b) memset(a,b,sizeof