Dividing
题目意思很清楚,这里就不再翻译了。初始的时候,我将他当作分组背包(估计是最近做分组背包做的太多了),来解,但一直超时,后来分析了一下时间复杂度为O(v*n),看了一下数据后,发现根本不可能过的去,v最大可有90000,而n最大有20000,这样怎么可能过的去。。。。。。后来看别人的解题报告的时候,发现可以用多重背包。然后我就对比了一下两者的情况。用分组背包的时候是这么考虑的:每类物品中可以选取一件,也可以选取两件。。。。而这些选择之间是互斥的,所以可用分组背包,而用多重背包更没问题。不过这个题目,用多重背包会更快,多重背包的复杂度为:O(v*sum(log num[i])),所以,直接按照模版写就可以过了。
#include <stdio.h>
#include <string.h>
int num[10] ;
int sum ;
int dp[100000] ;
int tag ;
#define INF -100000000
bool read(){
bool flag = 0 ;
sum = 0 ;
for(int i = 1 ; i <= 6 ; i ++){
scanf("%d" , &num[i]) ;
sum += num[i] * i ;
if(num[i])
flag = 1 ;
}
return flag ;
}
inline int max(int a , int b){
return a > b ? a : b ;
}
void ZeroOnePack(int cost , int weight){
for(int v = sum/2 ; v >= cost ; v--){
dp[v] = max(dp[v] , dp[v-cost] + weight) ;
if(dp[v]==sum/2){
tag = 1 ;
return ;
}
}
}
void CompletePack(int cost , int weight){
for(int v = cost ; v <= sum/2 ; v ++){
dp[v] = max(dp[v] , dp[v-cost] + weight) ;
if(dp[v]== sum/2){
tag = 1 ;
return ;
}
}
}
void MultiplePack(int cost ,int weight ,int amount){
if(cost * amount >= sum/2){
CompletePack(cost , weight) ;
return ;
}
int k(1) ;
while(k < amount){
ZeroOnePack(k * cost , k * weight) ;
if(tag)
return ;
amount = amount - k ;
k = k * 2 ;
}
ZeroOnePack(amount * cost , amount * weight) ;
return ;
}
void solve(){
//init
if(sum%2){
printf("Can't be divided.\n");
return ;
}
tag = 0 ;
for(int i = 1 ; i <= sum/2 ; i ++)
dp[i] = INF ;
for(int i = 1 ; i <= 6 ; i ++){
MultiplePack(i , i , num[i]) ;
if(tag)
break ;
}
if(tag){
printf("Can be divided.\n") ;
}
else{
printf("Can't be divided.\n") ;
}
}
int main(){
int t(0) ;
while(read()){
printf("Collection #%d:\n" , ++t) ;
solve() ;
printf("\n") ;
}
return 0 ;
}
然而这个题目也可以有其他的解法:直接搜索,不过需要注意剪枝。
#include <stdio.h>
#include <string.h>
int num[10] ;
int sum ;
int tag ;
bool read(){
bool flag = 0 ;
sum = 0 ;
for(int i = 1 ; i <= 6 ; i ++){
scanf("%d" , &num[i]) ;
if(num[i])
flag = 1 ;
sum += i * num[i] ;
}
return flag ;
}
void dfs(int c , int v){
if(v==sum / 2){
tag = 1 ;
return ;
}
if(tag)
return ;
for(int i = c ; i >= 1 ; i --){
if(num[i]){
if(v + i <= sum / 2){
num[i] -- ;
dfs(c , v + i) ;
if(tag)
return ;
}
}
}
return ;
}
void solve(){
tag = 0 ;
if(sum%2){
printf("Can't be divided.\n") ;
return ;
}
dfs(6 , 0) ;
if(tag){
printf("Can be divided.\n") ;
}
else{
printf("Can't be divided.\n") ;
}
}
int main(){
int t(0) ;
while(read()){
printf("Collection #%d:\n" , ++t) ;
solve() ;
printf("\n") ;
}
return 0 ;
}