挑战程序设计——贪心:2393 1017 3040 1862 3262

Poj 2393 

题意:酸奶厂可以存放任意数量的酸奶,每单位酸奶每周存储需要S元。第i周生产每单位酸奶要ci元,需要送yi单位酸奶给客户。问酸奶厂最低花费多少使得能按时给顾客送奶。

多刷题真的是很有用啊,没想到扇贝杯的时候就出了一道跟这差不多的题,但是我long long 用错了只得了80分

感觉自己真真是猪了,很多东西都重复计算了,价格一定是在上周的最小价上+S或者是本周生产的啊

突然感觉自己既想复杂又想简单了,所以有点懵。。orz

#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
typedef long long LL;
LL ans;
int n,s;
const int N=1e4+10;
int cost[N],del[N];
int main()
{
    //freopen("in.txt","r",stdin);
    cin>>n>>s;
    for(int i=1;i<=n;++i)
        cin>>cost[i]>>del[i];
    for(int i=2;i<=n;++i)
        cost[i]=min(cost[i],cost[i-1]+s);
    for(int i=1;i<=n;++i)
        ans+=cost[i]*del[i];
    cout<<ans<<endl;
    return 0;
}

 

poj 1017 packets

题意:有1*1*h 2*2*h ... 6*6*h规格的箱子,分别给出它们的数量,问用6*6*h的箱子去装这些箱子,最少需要多少个箱子

 

我的代码写的实在是太冗长了,而且还wa了,窒息

三处改进代码:

1、向上取整 (a[3]+3)/4    我分类讨论的来着_(:з」∠)_

2、 a[1]=max(0,a[1]-4*(5*a[4]-a[2]));   我用了冗长的循环 和分类_(:з」∠)_

3、考虑填充3*3剩下的位置时,可填充的2*2和1*1与3*3的个数有线性关系,我是一个个分类的_(:з」∠)_

多动点脑子,少写点废话

另一种思路,做加法不要做减法,把这么多箱子最多能放多少个算出来,会简单很多。。。

简单易懂的博客m(o_ _)m

poj 3040 Allowance

题意:Fj有N种面值的硬币,面值V,数量B,Fj想每周都给奶牛至少发C元的工资,问Fj最多能发多少周的工资。

每个周都要尽可能地给刚好C元,如果凑不到C元,那么就拿小的去补

贪心吧贪心策略又想不到,看了贪心策略吧代码又写得和shi一样

cnt数组记录要凑到不小于C,需要每种面值多少个,拿总数除以它,就知道这样能分配多少周,以节省时间

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,c;
const int N=25;
struct money
{
    int v;
    int b;
}m[N];
int cnt[25];
bool cmp(money p,money q)
{
    return p.v>q.v;
}
int main()
{
    scanf("%d%d",&n,&c);
    int ans=0;
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d",&m[i].v,&m[i].b);
    }
    sort(m+1,m+1+n,cmp);

    int i;
    for(i=1;i<=n;++i)
    {
        if(m[i].v>=c)
            ans+=m[i].b;
        else
            break;
    }
    if(i==n+1)
    {
        printf("%d\n",ans);
        return 0;
    }

    while(true)
    {
        memset(cnt,0,sizeof(cnt));
        int sum=c;
        for(int j=i;j<=n;++j)
        {
            if(m[j].b&&sum>0)
            {
                cnt[j]+=min(m[j].b,sum/m[j].v);                                 //需要的和剩下的小值,不能超过c
                sum-=cnt[j]*m[j].v;
            }

        }
        if(sum>0)
        {
            for(int j=n;j>=i;--j)
            {
                if(m[j].b&&sum>0)
                {
                    int tmp=min(m[j].b-cnt[j],(sum+m[j].v-1)/m[j].v);           //上面一轮取下来不够,就拿最小的去补,这样保证最小损失(大于c的部分最小)
                    if(tmp>0)                                                   //因为这里是允许超过c的,所以是向上取  注意cnt要>=0
                    {
                        sum-=tmp*m[j].v;
                        cnt[j]+=tmp;
                    }
                }
            }
        }
        if(sum>0)
            break;
        int tmp=0x3f3f3f3f;
        for(int j=i;j<=n;++j)
        {
            if(cnt[j])                              //忘了这一行犯了除零错误
                tmp=min(tmp,m[j].b/cnt[j]);

        }

        ans+=tmp;
        for(int j=i;j<=n;++j)
        {
            if(cnt[j])
                m[j].b-=tmp*cnt[j];
        }
    }
    printf("%d\n",ans);
    return 0;

}

poj 1862 哈夫曼编码、优先权队列

2\sqrt{2\sqrt{ab}*c}可以看出来,越先乘的数开次方次数越多,也就越小,因此每次选择最大的两个数

 

poj 3262 protecting flowers

题意:N只牛进了FJ的花园,将第i头牛送回去往返时间为2*Ti,若她被留在花园里,每分钟破坏di的花,问Fj合理安排送牛的顺序,破坏的花数最少?

假设牛A,送走a1,毁坏b1;牛B,送走a2,毁坏b2;

先送牛A后送牛B,损失2*a1*b2

先送牛B后送牛A,损失2*a2*b1

如果先送牛A更优,即a1*b2<a2*b1,即a1/b1<a2/b2,先送比值小的,为了避免余数等,直接用式子a1*b2<a2*b1排序即可

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
int n;
const int N=1e5+10;
struct cow
{
    int t;
    int d;
}c[N];
bool cmp(cow p,cow q)
{
    return p.t*q.d<q.t*p.d;
}
int main()
{
    scanf("%d",&n);
    int des=0;
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d",&c[i].t,&c[i].d);
        des+=c[i].d;
    }

    sort(c+1,c+1+n,cmp);
    LL ans=0;
    for(int i=1;i<=n;++i)
    {
        des-=c[i].d;            //花园里的牛每分钟破坏花的数目
        ans+=2*c[i].t*des;
    }
    printf("%lld\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值