lightoj 1180 二分+DP

题意:有N个工人,和两个大小均为M的工作,工人i完成单位1的a工作需要ta[i],完成单位1的b工作需要tb[i]时间,求问完成两份工作的最小时间

思路:

好吧这题想了好久没想出来,看了别人的思路

说实话看了别人的思路后发现真的很接近了

哎。。。一开始其实想到了 求dp[i][j]  表示 前i个人完成j的a工作做多能做b多少工作,但是当时不知道怎么转移

其实这里转移的话  还需要一个条件,那就是总时间是多少

然后我们二分搜索时间,用dp来判断是否能够在该时间内完成两个工作

然后状态转移方程的话直接看代码吧,很清楚了,代码中用了滚动数组来优化,其实优不优化影响不大

AC代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

const int MAX_N = 110, MAX_M = 110;

int dp[MAX_M], t_a[MAX_N], t_b[MAX_N];
int N, M;

bool judge( int mid ){
    memset( dp, -1, sizeof( dp ) );
    dp[0] = 0;
    for( int i = 0; i < N; i++ ){
        int temp = mid / t_a[i];
        for( int j = M; j >= 0; j -- ){
            for( int k = 0; k <= temp && k <= j; k++ ){
                if( dp[j-k] != -1 )dp[j] = max( dp[j], dp[j-k] + ( mid - k * t_a[i] ) / t_b[i] );
            }
        }
    }
    return dp[M] >= M;
}

int main(){
    int T, Case = 1;

    scanf( "%d", &T );
    while( T-- ){
        scanf( "%d%d", &N, &M );
        for( int i = 0; i < N; i++ ){
            scanf( "%d%d", &t_a[i], &t_b[i] );
        }
        int l = 0, r = 50000, mid;
        while( l <= r ){
            mid = ( l + r ) / 2;
            if( judge( mid ) ){
                r = mid - 1;
            }else{
                l = mid + 1;
            }
        }
        printf( "Case %d: %d\n", Case++, l );
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值