UVA - 12105 Bigger is Better DP

来源:互联网 发布:带文字单页源码 编辑:程序博客网 时间:2024/06/03 07:12

题目链接

题意很简单哦,就是用n根火柴拼出能被m整除的最大的数。这题一直困扰了我很久。。。本来是按照书上给的方法,dp[i][j]表示除以m余j的i位数需要的火柴数,刚开始想用记忆化搜索写,然而,在选择数字的时候出了问题,不知道该选大的还是该选火柴少的,恩 一定是功力不够,然后一直拖着好久,今天终于看到了老先生说的‘更简单的做法’,就是用dp[i][j]存储被m除余j的数的最大长度,i为火柴数,这样的话可以写出状态方程

dp[i][j]=max(dp[i][j],dp[i-nedd[k]][(j*10+k)%m]+1); 同时用一个同等规模的二元组ans来记录(i,j)状态下的最大数字即可。输出答案时往回推就可以了

#include <map>#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define INF 0x7f7f7f7fusing namespace std;const int c[]={6,2,5,5,4,5,6,3,7,6};const int maxn = 105;const int maxm = 3002;int n,m,dp[maxn][maxm],ans[maxn][maxm],cases=0;int main() {    while(~scanf("%d%d",&n,&m)&&n){        memset(dp,-1,sizeof(dp));        memset(ans,-1,sizeof(ans));        for(int i=0;i<=n;i++)            for(int j=0;j<m;j++){                if(j==0) dp[i][j]=0;                for(int k=9;k>=0;k--){                    if(i>=c[k]){                        if(dp[i-c[k]][(j*10+k)%m]>=0&&dp[i-c[k]][(j*10+k)%m]+1>dp[i][j]){                            dp[i][j]=dp[i-c[k]][(j*10+k)%m]+1;                            ans[i][j]=k;                        }                    }                }            }        printf("Case %d: ",++cases);        if (ans[n][0]<0) printf("-1");        else {            int i=n,j=0;            for(int d=ans[i][j]; d>=0; d=ans[i][j]) {                printf("%d",d);                i-=c[d];                j=(j*10+d)%m;            }        }        printf("\n");    }    return 0;}


0 0
原创粉丝点击