贪心:零散题目整理

对于数学弱鸡来说,对于贪心题目的感知只有直觉和不断试错...所以题目记录也是也当重要的一部分。而且贪心的代码比较零碎,是真的烦

区间调度问题,每项工作需要一定时间,在给定时间内完成尽可能多的工作数量。贪心按照结束时间排序


字典序最小问题,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");
}
posted @ 2020-10-09 17:02  太山多桢  阅读(102)  评论(0编辑  收藏  举报