nyoj 229

http://acm.nyist.net/JudgeOnline/problem.php?pid=229

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int MAXN = 110;

int Ap[MAXN];
int Bp[MAXN];
int dp[MAXN];//dp[i]表示完成i个工作A,之后还能完成多少个工作B
int n,m;

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

int slove( int mid )
{
    int i,j,k;
    memset(dp, -1, sizeof(dp));

    for(i = 0; i <= m; ++i)//第一个人完成i个A,还可以完成多少个B
        if(mid >= i*Ap[1])
            dp[i] = (mid-i*Ap[1])/Bp[1];
        else
            break;

    if(dp[m] >= m)//如果第一个人完成A之后,还有足够的时间来完成B,那么就说明这个mid时间是可以的
        return 1;
    //如果剩下的时间不足以完成B,或者给定mid的时间完不成A, 剩下的就是背包思想
    for(i = 2; i <= n; ++i)
    {//既然第一个人不能在给定的mid时间内完成两个任务,那么接下来在让其他人上,看前i是否可以完成任务
        for(j = m; j >= 0; --j)
        {
            for(k = 0; k <= j && k*Ap[i] <= mid; ++k)
            {//如果第i个人可以完成k份工作A,并且前i-1个人已完成了j-k个工作A,(即是否可以留更多的时间来做更多的工作)那么前i个工人还可以完成多少份工作?
                if(dp[j-k] != -1)
                    dp[j] = MAX(dp[j], dp[j-k]+(mid-k*Ap[i])/Bp[i]);
            }
        }
        if(dp[m] >= m)//如果前i(包括i)个工人完成A之后还能完成B,那么返回1,说明mid满足
            return 1;
    }
    return 0;
}

int main()
{
    int i,T;
    scanf("%d", &T);
    while(T--)
    {
        int maxtime = 0;
        scanf("%d%d",&n,&m);
        for(i = 1; i <= n; ++i)
        {
            scanf("%d%d",&Ap[i],&Bp[i]);
            maxtime = MAX(maxtime, MAX(Ap[i], Bp[i]));
        }

        int L = 0,R = (maxtime*m) << 1;
        while(L < R)
        {
            int mid = (L + R)>>1;

            if(slove(mid))//如果给定的mid时间一直都满足,那么继续收缩区间,直到找到一个最小的时间
                R = mid;
            else
                L = mid + 1;
        }
        printf("%d\n",L);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值