题意:有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;
}