POJ 1014 Dividing

33 篇文章 0 订阅

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 ;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值