hdu5188 二分 or 背包

题目关键在于,对于时间最少的方法,一定按照题目最早可以开始做的时间的顺序做,即按照l-t的从小到大顺序来做。

不妨假设1的开始时间小于2,那么一旦先做2,很明显从做完上件题目后的等待时间加长,因此可以得出最优解一定按照l-t的顺序做。

然后就是两种方法了,一种背包,一种二分,背包是求出了每个时间的最优值,而二分加dfs只是不断验证是否可行再二分的过程,事实证明,后者省去很多时间。

附代码:

背包:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
#include <stack>
#include <queue>
#include <map>
#include <vector>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define delf int m=(l+r)>>1
#define ll long long int

using namespace std;

int n,w;
int ans;
ll dp[3000010];

struct node
{
    int t,v,l;
} a[33];

bool cmp(node a1,node b1)
{
    if (a1.l-a1.t!=b1.l-b1.t)
        return a1.l-a1.t<b1.l-b1.t;
    return a1.l<b1.l;
}

ll max(ll a,ll b)
{
    return a>b?a:b;
}

int main()
{
    while (~scanf("%d%d",&n,&w))
    {
        memset(dp,0,sizeof(dp));
        int s1=0;
        int s2=0;
        int l=0;
        for (int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&a[i].t,&a[i].v,&a[i].l);
            s1+=a[i].v;
            s2+=a[i].t;
            l=max(l,a[i].l);
        }
        if (s1<w)
        {
            printf("zhx is naive!\n");
            continue ;
        }
        s2+=l;
        sort(a+1,a+n+1,cmp);
        int ans=s2;
        for (int i=1;i<=n;i++)
        {
            for (int t=s2;t>=a[i].l&&t>=a[i].t;t--)
            {
                dp[t]=max(dp[t],dp[t-a[i].t]+a[i].v);
                if (dp[t]>=w&&t<ans)
                    ans=t;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

二分:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
#include <stack>
#include <queue>
#include <map>
#include <vector>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define delf int m=(l+r)>>1
#define ll long long int

using namespace std;

int n,w;
int ans;
int sum[31];

struct node
{
    int t,v,l;
} a[31];

bool cmp(node a1,node b1)
{
    return a1.l-a1.t<b1.l-b1.t;
}

void dfs(int s,int t,int p)
{
    if (ans==1)
        return ;
    if (p>=w)
    {
        ans=1;
        return ;
    }
    if (s<=0||t<1)
        return ;
    if (p+sum[t]<w)
        return ;
    if (s>=a[t].l&&s>=a[t].t)
        dfs(s-a[t].t,t-1,p+a[t].v);
    dfs(s,t-1,p);
    return ;
}

int max(int a,int b)
{
    return a>b?a:b;
}

int main()
{
    while (~scanf("%d%d",&n,&w))
    {
        memset(sum,0,sizeof(sum));
        int s1=0;
        int s2=0;
        int p=0;
        for (int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&a[i].t,&a[i].v,&a[i].l);
            s1+=a[i].v;
            s2+=a[i].t;
            p=max(p,a[i].l);
        }
        sort(a+1,a+n+1,cmp);
        s2+=p;
        sum[0]=0;
        for (int i=1;i<=n;i++)
        {
            sum[i]=sum[i-1]+a[i].v;
        }
        if (s1<w)
        {
            printf("zhx is naive!\n");
            continue ;
        }
        int l=1;
        int h=s2;
        while (l<=h)
        {
            int m=(l+h)>>1;
            ans=0;
            dfs(m,n,0);
            if (ans==1)
                h=m-1;
            else
                l=m+1;
        }
        printf("%d\n",l);
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值