3.15课程总结——贪心

本周两堂课讲了很多贪心的题目,更新了我对贪心题目的认识,贪心题目的变化真的很多,贪心的策略更是各种各样。

POJ-1862-Stripies

Problem Description

Our chemical biologists have invented a new very useful form of life
called stripies (in fact, they were first called in Russian -
polosatiki, but the scientists had to invent an English name to apply
for an international patent). The stripies are transparent amorphous
amebiform creatures that live in flat colonies in a jelly-like
nutrient medium. Most of the time the stripies are moving. When two of
them collide a new stripie appears instead of them. Long observations
made by our scientists enabled them to establish that the weight of
the new stripie isn’t equal to the sum of weights of two disappeared
stripies that collided; nevertheless, they soon learned that when two
stripies of weights m1 and m2 collide the weight of resulting stripie
equals to 2sqrt(m1m2). Our chemical biologists are very anxious to
know to what limits can decrease the total weight of a given colony of
stripies. You are to write a program that will help them to answer
this question. You may assume that 3 or more stipies never collide
together.

input

The first line of the input contains one integer N (1 <= N <= 100) -
the number of stripies in a colony. Each of next N lines contains one
integer ranging from 1 to 10000 - the weight of the corresponding
stripie.

Output

The output must contain one line with the minimal possible
total weight of colony with the accuracy of three decimal digits after
the point.

Sample Input

3 72 30 50

Sample Output

120.000

题意: 给出n 个物体,分别给出每个的质量,并且两个物体(假设质量分别为m1,m2)相撞的时候变成一个物体,质量为2sqrt(m1m2),并且只会出现两个两个物品碰撞的情况,问最终能得到的物体的最小质量是多少。

思路:设质量为a, b, c,令a > b > c >,则有:
Ans = sqrt(sqrt(2 * a * b) * c * 2) or
Ans = sqrt(2 * a * sqrt(2 * b * c))
可见在一式中最大数a被两次开根,而二式中只一次开根,那么一式要比二式更优,于是每次选择最大的两个数开根计算,让大数尽量多被开根答案最小.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
int main()
{
	int n;
	double num;
	while(scanf("%d",&n)!=EOF)
	{
		priority_queue<double>q;
		while(n--)
		{
			cin>>num;
			q.push(num);
		}
		double ans=q.top();
		while(q.size()>1)
		{
			double a=q.top();
			q.pop();
			double b=q.top();
			q.pop();
			ans=2*sqrt(a*b);
			q.push(ans);
		}
		printf("%.3f\n",ans);
	}
	return 0;
}

HDU3183 A Magic Lamp

Problem Description

Kiki likes traveling. One day she finds a magic lamp, unfortunately the genie in the lamp is not so kind. Kiki must answer a question, and then the genie will realize one of her dreams.
The question is: give you an integer, you are allowed to delete exactly m digits. The left digits will form a new integer. You should make it minimum.
You are not allowed to change the order of the digits. Now can you help Kiki to realize her dream?

Input

There are several test cases. Each test case will contain an
integer you are given (which may at most contains 1000 digits.) and
the integer m (if the integer contains n digits, m will not bigger
then n). The given integer will not contain leading zero.

Outpu

For each case, output the minimum result you can get in one
line. If the result contains leading zero, ignore it.

Sample Input

178543 4 1000001 1 100001 2 12345 2 54321 2

Sample Output

13 1 0 123 321

题意:对于一个序列A[1…N],一共N个数,除去M个数使剩下的数组成的整数最小。也就是说在A[1…N]中顺次选取N-M个数,使值最小.(逆向思路,找删除的数不好找,就转化成找剩下的数字)

思路:既然要选取N-M个,那么可以容易知道这N-M位数的每一位一定在数组A中的区间。我们就可以这样做了:
第一位可以在区间[1,M+1]里面找,假设第一位在位置x,因为第二位肯定在第一位的后面,所以第二位一定存在于区间[x+1,M+2],为什么是M+2,因为第一位已经确定了,现在只需要确定N-M-1位了,所以区间就可以向后增加1。
一直这样循环下去,就可以找到了。

#include <iostream>
#include<cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
char num[1010];
char ans[1010];
int main()
{
    int i,temp,m,t,k;
    while(scanf("%s%d",num,&m)!=EOF)
    {
        t=0;
        k=0;
        int len=strlen(num)-m;
        while(len--)
        {
            temp=t;
            for(i=t; i<=m; ++i)
            {
                if(num[temp]>num[i])
                    temp=i;
            }
            ans[k++]=num[temp];
            m++;
            t=temp+1;
        }
        i=0;
        while(ans[i]=='0'&&i<k)//去除前导零
            i++;
        if(i==k)
            printf("0\n");
        else
        {
            for(; i<k; ++i)
                printf("%c",ans[i]);
            printf("\n");
        }
    }
    return 0;
}

zoj 3627 Treasure Hunt II (贪心)

Problem Description

There are n cities(1, 2, … ,n) forming a line on the wonderland. city i and city i+1 are adjacent and their distance is 1. Each city has many gold coins. Now, Alice and her friend Bob make a team to go treasure hunting. They starts at city p, and they want to get as many gold coins as possible in T days. Each day Alice and Bob can move to adjacent city or just stay at the place, and their action is independent. While as a team, their max distance can’t exceed M.

Input

The input contains multiple cases. The first line of each case are two
integers n, p as above. The following line contain n interger,“v1 v2
… vn” indicate the gold coins in city i. The next line is M, T.
(1<=n<=100000, 1<=p<=n, 0<=vi<=100000, 0<=M<=100000, 0<=T<=100000)

Output

Output the how many gold coins they can collect at most.

Sample Input

6 3
1 2 3 3 5 4
2 1

Sample Output

8

Hint

At day 1: Alice move to city 2, Bob move to city 4.

They can always get the gold coins of the starting city, even if T=0

思路:
由于每次只能走一步,那么一定是一个人往左走,一个人往右走,因为如果两个人一起往同一个方向走,那么就和一个人一起走的效果是一样的。

这里题目还有一个限制:两个人的相差距离不能超过m,那么,就可以让两个人先走到相距m米处。然后, 两个人同时一起往左边走,或者同时一起往右边走,这样就能保证两人的距离一直保持在m米内,又保证尽量获取更大长度区间的金币。

枚举两个人最开始走到相距m处的左右两点位置,然后再看剩下的时间还可以再继续一起往左或者往右继续走多远,最终取最大值的情况即可。需要注意边界的处理.

先找出能取得最多金币的区间,再选择往哪一方向走能取得最大值。

#include <iostream>
#include<cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 100010;
int n, m, t, p;
long long val[MAXN];
long long sum[MAXN];
long long func(long long *sum, int p)
{

    long long ans = val[p];
    for (int r = min(n, p + t); r >= p; --r)
    {
        int l = max(1, max(1, r - m));
        l = max(p-t, l);
        int rest_t = t - max(p-l, (r-p));
        int l1 = max(1, l - rest_t);
        int r1 = min(n, r + rest_t);
        ans = max(ans, max(sum[r]-sum[l1-1], sum[r1]-sum[l-1]));
    }
    return ans;
}
int main()
{

    while (scanf("%d%d", &n, &p))
    {

        sum[0] = 0;
        for (int i = 1; i <= n; ++i)
        {
            cin >> val[i];
            sum[i] = sum[i-1] + val[i];//前缀和
        }
        scanf("%d%d", &m, &t);
        long long ans = func(sum, p);
        for (int i = 1; i <= n/2; ++i)
            swap(val[i], val[n+1-i]);
        for (int i = 1; i <= n; ++i)
            sum[i] = sum[i-1] + val[i];
        ans = max(ans, func(sum, n+1-p));
        cout << ans << endl;
    }
    return 0;
}


本周讲的题目太多了,还没有消化好,ppt里的题还要继续去看,里面都是老师精选的贪心好题,他们都有独特的贪心思路,不像我做的那些贪心水题的思路那么好想。课上听课也有一些吃力了,stl还没怎么应用过,而老师很多题用了stl的方法,如果不熟悉就会掉队了,所以要再去复习应用stl。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值