码迷,mamicode.com
首页 > 其他好文 > 详细

code1047 邮票面值设计

时间:2016-05-03 23:28:29      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:

dfs+dp

dfs枚举每种情况,每层递归确定第k个数i:i = a[k-1]+1 to a[k-1]*n+1

当枚举完一个序列时,使用check()测试它能达到的max

使用dp。设dp[i]为凑成面值为i的最少张数

for(int k=1;a[k]<=i&&k<=t;k++){
    if(dp[i-a[k]]<n){
        dp[i]=min(dp[i], dp[i-a[k]]+1);
    }
}

注意dp[i]一开始要设成最大值

 

代码如下:

#include<iostream>
#include<cstring>
#define Size 41
using namespace std;

int a[Size];
int dp[10005];
int best[Size];
int n,t;//n张 t种 
int num=0;void save(int x){
    num=x;
    for(int i=1;i<=t;i++){
        best[i]=a[i];
    }
}

int check(){
    //memset(dp,0x3f,sizeof(dp));
    dp[0]=0;
    int ans=0;
    bool ok=true;
    
    //for(int i=1;i<=t;i++)cout<<a[i]<<" ";
    //cout<<endl;
    
    for(int i=1;ok;i++){
        ok=false;
        dp[i]=0x3f3f3f3f;
        for(int k=1;a[k]<=i&&k<=t;k++){
            if(dp[i-a[k]]<n){
                dp[i]=min(dp[i], dp[i-a[k]]+1);
                ok=true;
            }
        }
        if(ok)ans=i;
        
        //cout<<dp[i]<<‘ ‘;
    }
    //cout<<endl<<endl;
    
    return ans;
}

void dfs(int k){if(k>t){
        int x=check();
        if(x>num)save(x);
        return;
    }
    
    for(int i=a[k-1]+1;i<=n*a[k-1]+1;i++){
        a[k]=i;
        dfs(k+1);
    }
}

int main(){
    cin>>n>>t;
    
    a[1]=1;
    num=1;
    
    dfs(2);
    
    for(int i=1;i<=t;i++){
        cout<<best[i]<< ;
    }
    cout<<endl<<"MAX="<<num<<endl;
    cout<<f;
    return 0;
} 

By the way:a[1]一定是1!

 

PS:你可以看到我把check的第一行memset注释掉了,因为大部分时候很长的dp数组后面的很多元素都没有用(max没有那么大),所以只需要在循环里用到一个写一个dp[i]=x03f3f3f3f就可以了。memset使程序变得很慢很慢。(真的很慢啊...)(你真的不需要再试它有多慢了,因为我已经花一个小时帮你试了无数遍了...)

 

如果想继续优化,可以边dfs边维护dp和当前max2的值,这样dfs循环就可以写成这样:

i = a[k-1]+1 to max2+1

如果i>max2+1,那么max2+1这个数将始终无法凑成,结果不会更优

 

code1047 邮票面值设计

标签:

原文地址:http://www.cnblogs.com/FuTaimeng/p/5456677.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!