两道中等贪心题,poj 3040, poj 3190

来源:互联网 发布:君理资本 知乎 编辑:程序博客网 时间:2024/06/09 23:26

POJ 3190  Stall Reservations

思路:利用优先队列,先对区间左端点从小到大排序,优先队列以区间右端点小的为优先级。

#include <stdio.h>#include <string.h>#include <algorithm>#include <queue>using namespace std;struct dd{    int l;    int r;    int ps;    friend bool operator<(struct dd k1,struct dd k2){        return k1.r>k2.r;//以右端点小的为优先级,使得队首的牛是最早使用完机器的牛。    }}ss[50005];typedef struct dd dd;bool cmp(dd a,dd b){    return a.l<b.l;}int main(){    int n;    while(scanf("%d",&n)!=EOF){        int s[50005],need=1;//need为需要的机器数,s[i]表示输入时顺序为i的牛所使用的机器编号。        for(int i=0;i<n;i++){            scanf("%d%d",&ss[i].l,&ss[i].r);            ss[i].ps=i;//记录牛的输入时顺序,因为后面sort会打乱顺序。        }        sort(ss,ss+n,cmp);        priority_queue<dd> q;        q.push(ss[0]);        s[ss[0].ps]=1;        for(int i=1;i<n;i++){            if(ss[i].l<=q.top().r)//如果队首的牛还在使用机器,则需再拿一台机器。                s[ss[i].ps]=++need;            else{//如果队首的牛已经使用完机器,则使用他的机器。                s[ss[i].ps]=s[q.top().ps];                q.pop();            }            q.push(ss[i]);        }        printf("%d\n",need);        for(int i=0;i<n;i++)            printf("%d\n",s[i]);    }    return 0;}


POJ 3040 Allowance

思路:面额大于c的直接给。对于小于c的,先取面额大的,取到不能再取(即再取就会溢出),然后取面额小的取,使得工资尽可能的接近c。

#include <stdio.h>#include <string.h>#include <algorithm>#define INF 10000000using namespace std;struct dd{    int v;    int b;}uu[22];int tt[22];//tt[i]表示在其中一种组合方式中,第i个面值的所需要的个数(不完全是,见34行)。bool cmp(struct dd a,struct dd b){    return a.v>b.v;}int main(){    int n,c;    while(scanf("%d%d",&n,&c)!=EOF){        int k=0,sum=0;        for(int i=0;i<n;i++){            int x,y;            scanf("%d%d",&x,&y);            if(x>=c) sum+=y;//面值超出c的直接就可以给。            else{                uu[k].v=x;                uu[k++].b=y;            }        }        sort(uu,uu+k,cmp);        while(1){//枚举所有工资的组合方式。            int t=c;            memset(tt,0,sizeof(tt));            for(int i=0;i<k;i++){                tt[i]+=min(t/uu[i].v,uu[i].b);//如果第i个面值的纸币实际数量不够,则直接存储实际数量。                t-=tt[i]*uu[i].v;                if(t<0){                    t+=tt[i]*uu[i].v;//不能溢出。                    tt[i]=0;//不取                    break;                }                else if(t==0) break;            }            if(t>0){                for(int i=k-1;i>=0;i--){                    if(uu[i].b){                        if(uu[i].b<=tt[i]) continue;// !!!                         int s=t%uu[i].v?t/uu[i].v+1:t/uu[i].v;//除法可加快速度。                        s=min(s,uu[i].b);                        tt[i]+=s;                        t-=s*uu[i].v;                        if(t<=0) break;                    }                }            }            if(t>0) break;            int d=INF;//可发的周数。            for(int i=0;i<k;i++){                if(tt[i])                    d=min(d,uu[i].b/tt[i]);            }            sum+=d;            for(int i=0;i<k;i++){                uu[i].b-=d*tt[i];//更新每种纸币的数量。            }        }        printf("%d\n",sum);    }    return 0;}/*3 64 32 21 1*/


0 0
原创粉丝点击