POJ 3262 Protecting the Flowers

Description

Farmer John went to cut some wood and left N (2 ≤ N ≤ 100,000) cows eating the grass, as usual. When he returned, he found to his horror that the cluster of cows was in his garden eating his beautiful flowers. Wanting to minimize the subsequent damage, FJ decided to take immediate action and transport each cow back to its own barn.

Each cow i is at a location that is Ti minutes (1 ≤ Ti ≤ 2,000,000) away from its own barn. Furthermore, while waiting for transport, she destroys Di (1 ≤ Di ≤ 100) flowers per minute. No matter how hard he tries, FJ can only transport one cow at a time back to her barn. Moving cow i to its barn requires 2 × Ti minutes (Ti to get there and Ti to return). FJ starts at the flower patch, transports the cow to its barn, and then walks back to the flowers, taking no extra time to get to the next cow that needs transport.

Write a program to determine the order in which FJ should pick up the cows so that the total number of flowers destroyed is minimized.

Input

Line 1: A single integer  N 
Lines 2.. N+1: Each line contains two space-separated integers,  Ti and  Di, that describe a single cow's characteristics

Output

Line 1: A single integer that is the minimum number of destroyed flowers

Sample Input

6
3 1
2 5
2 3
3 2
4 1
1 6

Sample Output

86


题意:
有n个牛在FJ的花园乱吃花朵,所以FJ要赶他们回牛棚。每个牛在被赶走之前每分钟吃Di个花朵。赶它回去FJ要花的时间是Ti。在被赶走的过程中牛就不能乱吃了。


贪心。T/D越小就应该越早赶回去,证明如下:
假设序列都由二元组组成,二元组是由T和D组成,那么对一个序列有相邻的两头牛是这样的
..........(T1, D1) , (T2, D2)....................
如果(T1 , D1)和(T2 , D2)交换位置了
变成新序列
..........(T2 , D2) , (T1 , D1 ).....................
假设在这之前FJ已经花了x时间了。
那么赶完这两头牛的损失的量就分别为
x*D1 + (x + 2*T1 ) * D2
x*D2 +(x + 2*T2 ) * D1
二者做差
得到 T1D2 - D1T2 
 T1D2 < D1T2 ,则有第一个序列优于第二个
即 T1/D1 < T2/D2 ;
那么对于任意的序列,我们都可以通过若干次这种相邻的交换使得序列变成最优的。
证明完毕。


刚开始自己想利用函数解析式分析出满足什么样条件的牛应该越早被赶回去,结果没分析出来。看了别人的才知道,可以将两种相反的决策相比较,比如做差,然后再从中分析。


#include "cstdio"
#include "algorithm"
using namespace std;

struct node
{
	int T,D;
}cow[1000005];
long long s[1000005];

bool cmp(node x,node y)
{
	return x.T*1.0/x.D < y.T*1.0/y.D;
}

int main(int argc, char const *argv[])
{
	int N;
	while(~scanf("%d",&N))
	{
		for(int i = 0;i < N;i++)
			scanf("%d%d",&cow[i].T,&cow[i].D);
        sort(cow,cow+N,cmp);
        
        long long ans = 0;
        for(int i = N-1;i > 0;i--)
        {
        	ans += cow[i].D;
        	s[i-1] = ans;
        }
        s[N-1] = 0;

        ans = 0;
        for(int i = 0;i < N;i++)
        {
        	ans += s[i]*cow[i].T*2;
        }
        printf("%lld\n",ans);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值