贪心:零散题目整理
对于数学弱鸡来说,对于贪心题目的感知只有直觉和不断试错...所以题目记录也是也当重要的一部分。而且贪心的代码比较零碎,是真的烦
区间调度问题,每项工作需要一定时间,在给定时间内完成尽可能多的工作数量。贪心按照结束时间排序
字典序最小问题,POJ3617。对给定一个字符串,重新构造为一个新的字符串。每次可以从S剩余部分的最前或最后去一个字符,使新字符串字典序最小。若当前最前最后字符相同,应该比较下一层,直到出现结果。
#include<stdio.h>
int n,loc;
char s[2005],ans[2005];
int main(){
scanf("%d",&n);
char str[5];
for(int i=0;i<n;i++){
scanf("%s",str);
s[i]=str[0];
}
int l=0,r=n-1;
while(l<=r){
bool f=false;
for(int i=0;l+i<=r;i++){
if(s[l+i]<s[r-i]){
f=true;
break;
}
if(s[l+i]>s[r-i]){
f=false;
break;
}
}
if(f) ans[loc++]=s[l++];
else ans[loc++]=s[r--];
}
for(int i=0;i<loc;i++){
printf("%c",ans[i]);
if((i+1)%80==0) printf("\n");
}
}
POJ3190,和优先队列配合。思路比较好想,和POJ2376类似,但是编程有点麻烦,没有选到合适的数据结构所以TLE了几回
POJ1017,思路明确:先放大的放不了大的再放小的。一开始是将空格分隔递归,发现分割不行;递归太复杂写不出来。看了代码直接不同大小时分情况处理,反正只有6层...问题不能想得太复杂...
POJ3040,思路不好想而且不好写。要发尽可能多的天数,应该尽可能地避免浪费。所以对于钱不够的情况,应当从大到小贪心去取,但是这个过程是不会超过限制的;若遍历完发现没有取够,再从小到大取,尽可能避免溢出的浪费。
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
int n,c,ans,use[25];
const int inf=0x7fffffff;
struct coin{
int v,num;
bool operator < (const coin &x) const{
return v>x.v;
}
}coins[25];
int main(){
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++){
scanf("%d%d",&coins[i].v,&coins[i].num);
if(coins[i].v>=c){
ans+=coins[i].num;
coins[i].num=0;
}
}
sort(coins+1,coins+n+1);
while(true){
memset(use,0,sizeof(use));
int cost=c;
bool flag=false;
for(int i=1;i<=n;i++){
if(coins[i].num){
use[i]=min(coins[i].num,cost/coins[i].v);
cost-=use[i]*coins[i].v;
if(cost==0){
flag=true;
break;
}
}
}
if(cost){
for(int i=n;i>=1&&!flag;i--){
if(coins[i].num>use[i]){
cost-=coins[i].v;
use[i]++;
if(cost<=0){
flag=true;
break;
}
}
}
}
if(!flag) break;
int maxn=inf;
for(int i=1;i<=n;i++){
if(use[i]){
maxn=min(coins[i].num/use[i],maxn);
}
}
ans+=maxn;
for(int i=1;i<=n;i++){
if(use[i]){
coins[i].num-=maxn*use[i];
}
}
}
printf("%d\n",ans);
}
POJ3262,完全没思路。应当是d/t排序,大的在前面优先处理。具体推导可以见题解。一个类似的题,洛谷P1080
//POJ3262
#include<stdio.h>
#include<algorithm>
using namespace std;
int n;
struct cow{
long long d,t;
double s;
bool operator < (const cow &x) const{
return s>x.s;
}
}cows[100005];
long long sum,ans;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&cows[i].t,&cows[i].d);
cows[i].s=(double)cows[i].d/(double)cows[i].t;
sum+=cows[i].d;
}
sort(cows+1,cows+n+1);
for(int i=1;i<=n;i++){
sum-=cows[i].d;
ans+=sum*2*cows[i].t;
}
printf("%lld\n",ans);
}
POJ3614,先对牛排序,如果一个一个考虑每头牛能不能满足,不太好确定贪心策略。那么考虑对每瓶防晒霜的处理,将满足条件的牛放入队列中处理,直到防晒霜用完或牛结束
#include<stdio.h>
#include<queue>
#include<algorithm>
using namespace std;
int c,l;
long long num[2500];
struct cow{
int minn,maxn;
bool operator < (const cow &x) const{
if(minn!=x.minn) return minn<x.minn;
else return maxn<x.maxn;
}
}cows[2505];
struct bot{
int num,cnt;
bool operator < (const bot &x) const{
return num<x.num;
}
}bot[2505];
priority_queue<int,vector<int>,greater<int> > que;
int main(){
scanf("%d%d",&c,&l);
for(int i=1;i<=c;i++){
scanf("%d%d",&cows[i].minn,&cows[i].maxn);
}
sort(cows+1,cows+c+1);
for(int i=1;i<=l;i++){
int a,b;
scanf("%d%d",&bot[i].num,&bot[i].cnt);
}
sort(bot+1,bot+l+1);
int ans=0,loc=0;
for(int i=1;i<=l;i++){
while(loc<=c&&cows[loc].minn<=bot[i].num){
que.push(cows[loc].maxn);
loc++;
}
while(!que.empty()&&bot[i].cnt){
if(que.top()>=bot[i].num){
ans++;
bot[i].cnt--;
}
que.pop();
}
}
printf("%d\n",ans);
}
POJ1456,也是要和优先队列结合。从后面开始考虑,把时间触发的商品放入优先队列。
对于贪心和优先队列结合的问题,一般是对于每个被选择的物品,有两个属性充当范围。这时以另一个商品的相关属性充当基准,把符合条件的第一中物品放入优先序列贪心即可。
POJ2010,因为最后结果只与中位数成绩有关与其他成绩无关,那么对每个成绩进行记录比他小的成绩里最小的(n-1)/2个f的和,以及比他大的成绩里最小的(n-1)/2个f的和。最后二分就行
#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;
int n,c,f,h,left[100005],right[100005],ans;
struct cow{
int s,f;
bool operator < (const cow &x) const{
return s<x.s;
}
}cows[100005];
priority_queue<int> que;
int main(){
scanf("%d%d%d",&n,&c,&f);
for(int i=1;i<=c;i++){
scanf("%d%d",&cows[i].s,&cows[i].f);
}
sort(cows+1,cows+c+1);
h=(n-1)/2;
int sum=0;
while(!que.empty()) que.pop();
for(int i=1;i<=c;i++){
left[i]=sum;
if(i<=h){
sum+=cows[i].f;
que.push(cows[i].f);
}
else{
if(cows[i].f<que.top()){
sum-=que.top();
que.pop();
que.push(cows[i].f);
sum+=cows[i].f;
}
}
}
sum=0;
while(!que.empty()) que.pop();
for(int i=c;i>=1;i--){
right[i]=sum;
if(c-i+1<=h){
sum+=cows[i].f;
que.push(cows[i].f);
}
else{
if(cows[i].f<que.top()){
sum-=que.top();
que.pop();
que.push(cows[i].f);
sum+=cows[i].f;
}
}
}
bool flag=false;
for(int i=c-h;i>=h+1;i--){
if(left[i]+cows[i].f+right[i]<=f){
flag=true;
printf("%d\n",cows[i].s);
return 0;
}
}
if(!flag) printf("-1\n");
}