本周两堂课讲了很多贪心的题目,更新了我对贪心题目的认识,贪心题目的变化真的很多,贪心的策略更是各种各样。
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 1Sample 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。