UVA 12105 Bigger is Better

Big is Better

题目大意:用火柴拼数字,每个数字需要的火柴如下图,共有n(n<=100)个火柴,要求拼出的数能整除m(m<=3000),求所能拼出的最大的数字是多少。

360反馈意见截图16550429607465

思路:按位进行DP,dp[i][j]表示用i位数表示出除以m余j的数最少需要多少根火柴棒,如果不存在则为inf,最后得到最大的i满足dp[i][0]存在,则最大位数为i,令high=i

然后从第high位开始枚举,先从9开始,如果填9可以,等价于dp[high-1][(m-9xxxxx)%m]+f[9]<=n,相当于这一位先用掉了f[9]=6根火柴,再用剩下的火柴一定能够摆出剩下的数字才可以,否则就不行。一直往下枚举。

代码如下:

//https://cn.vjudge.net/problem/UVA-12105
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 3003
const int inf=0xfffffff;
using namespace std; 
int f[]={6,2,5,5,4,5,6,3,7,6};
int dp[202][N],n,m,ans,sum,mi[202],dig[202];

void init(){
	mi[0]=1;
	for(int i=0;i<202;i++){
		for(int j=0;j<=m;j++){
			dp[i][j]=inf;
		}
		if(i){
			mi[i]=(10*mi[i-1])%m;
		}
	}
	
}
int cal(int a,int b){
	return (a*mi[b])%m;
}
int cal2(int x)
{
	int ans=0;
	while(x){
		ans+=f[x%10];
		x/=10;
	}
	return ans;
}
//#define GLQ 1
int main()
{
	#ifdef GLQ  
    freopen("input.txt","r",stdin);  
    freopen("out2.txt","w",stdout);  
	#endif // GLQ 
	int T=0;
	while(scanf("%d",&n),n){
		printf("Case %d: ",++T);
		int high=0;
		scanf("%d",&m);
		init();
		for(int i=0;i<10;i++){
			dp[0][0]=0;
			dp[1][i%m]=min(dp[1][i%m],f[i]);
			if(dp[1][i%m]>n) dp[1][i%m]=inf;
		}
		for(int i=1;;i++){
			bool flag=0;
			for(int j=0;j<m;j++){
				for(int x=0;x<10;x++){
					dp[i+1][(j+cal(x,i))%m]=min(dp[i+1][(j+cal(x,i))%m],dp[i][j]+f[x]);
					if(dp[i+1][(j+cal(x,i))%m]>n) dp[i+1][(j+cal(x,i))%m]=inf;
					else flag=1;
					
				}
			}
			if(dp[i][0]!=inf) high=i;
			if(!flag) {
				break;
			}
		}
		int cnt=0;
		int tmpn=n;
		int tmpm=m ;
		if(!high){
			printf("-1\n");
			continue;
		}
		for(int i=high;i>0;i--){
			for(int j=9;j>=0;j--){
				if(dp[i-1][(tmpm-cal(j,i-1)+m)%m]+f[j]<=tmpn){//n和m需要修改 
					tmpn-=f[j];
					dig[cnt]=j;
					tmpm=(tmpm-cal(j,i-1)+m)%m;
					cnt++;
	
					break;
				}
			}

		}

		for(int i=0;i<high;i++){
			printf("%d",dig[i]);
		}
		printf("\n");
		
	}
	return 0;
}
posted @ 2017-05-26 19:42  CRAZYC4T  阅读(190)  评论(0编辑  收藏  举报