POJ 1014 Dividing

来源:互联网 发布:表格筛选重复数据 编辑:程序博客网 时间:2024/04/30 06:20

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



原创粉丝点击