很好的一道题目。
思路:
先求出哪些货物的组合能一次用两辆车运走,然后再对这些组合DP。
dp[j]代表能运走(j)中组合的的货物的最少次数。。。
状态转移方程:dp[j|onestep[i]] = min( dp[j|onestep[i]], dp[j] + 1 );(注意。。。代码中已经保证 一次运走(j)组合、(onestep[i])组合是可行的。。。所以这个方程才成立。。。)
#include <iostream>
using namespace std;
const int MAX = 0x3f3f3f3f;
bool mark[1030];
int N, C1, C2;
int w[10];
int dp[1030];
int onestep[1030];//用来记录能一次运走的状态
bool judge( int n ){//DP 其实也是DP的思想
int sum = 0;
memset( mark, false, sizeof( mark ) );
mark[0] = true;
//DP的思想........
for( int i = 0; i < N; i++ ){//判断在(n)里面的货物中C1能一次运走哪些数量的货物(恰好运走而不是能够运走)
if( n & ( 1 << i ) ){
sum += w[i];
for( int j = C1; j >= w[i]; j-- ){
if( mark[j-w[i]] ){
mark[j] = true;
}
}
}
}
if( sum > C1 + C2 ){
return false;
}
for( int i = 0; i <= C1; i++ ){
if( mark[i] && sum - i <= C2 ){//上面求出了恰好运走的货物重量,然后判断剩余重量C2能不能运走
return true;
}
}
return false;
}
inline int min( int a, int b ){
return ( a < b ? a : b );
}
int main(){
int T, Case = 1;
cin >> T;
while( T-- ){
cin >> N >> C1 >> C2;
for( int i = 0; i < N; i++ ){
cin >> w[i];
}
int total = 0;
for( int i = 1; i < ( 1 << N ); i++ ){//求出哪些状态能一次运走....
if( judge( i ) ){
onestep[total++] = i;
}
}
memset( dp, 0x3f, sizeof( dp ) );
dp[0] = 0;
for( int i = 0; i < total; i++ ){//DP........(恰能运走....)
for( int j = ( 1 << N ) - 1; j >= 0; j-- ){
if( dp[j] == MAX ){
continue;
}
if( ( j & onestep[i] ) == 0 ){
dp[j|onestep[i]] = min( dp[j|onestep[i]], dp[j] + 1 );
}
}
}
cout << "Scenario #"<< Case++ <<":" << endl;
cout << dp[(1<<N)-1] << endl;
cout << endl;
}
return 0;
}