时间:1s 空间:256M
题目描述:
小信有n根木棍,他想拼出只包含给定的m种数字中的至少一种数字的数字串。
已知数字1,2,3,4,5,6,7,8,9分别需要2,5,5,4,5,6,3,7,6根火柴。要求n根木棍全部都用完且拼成的数字最大,输出这个数字。保证答案存在。
输入格式:
第一行包含两个整数 n,m,表示木棍数量和给定数字种类数。
第二行包含m个数a1,a2...am,表示给定的数字,保证数字互不相同。
输出格式:
输出一串数字表示答案。
样例1输入:
20 4
3 4 8 7
样例1输出:
777773
约定与提示:
对于100%的数据,2≤n≤104,1≤m,ai≤9,
样例解释:
777773 需要 5∗3+1∗5=20根木棍。
题意:
用n根火柴,可以拼m种数字,用这些火柴拼出的数字要尽可能的大
思路:
此题是完全背包,而代价(v[i])就是用去的火柴数,问题是这道题一个难点在于怎么样数字更大,那我们可以先比位数,比完位数,比各个位的大小,普通完全背包转移方程为:
f[j]=max(f[j],f[j-v[i]]+w[i])
将此状态转移方程改成按位数比较(改为高精度),此题要恰好用完,就是恰好装满背包所以要把初始化改成0。
代码:
#include<bits/stdc++.h>
using namespace std;
long long a[10005],len=0,times;
long long f[10005];
int quantity[10]={0,2,5,5,4,5,6,3,7,6};//每个数字所需火柴数因为数组从0开始记所以有0
int cmp(int x,int y) {
return x>y;
}
int main(){
int n,m;
cin>>n>>m;
memset(f,-1,sizeof(f));
for(int i=1;i<=m;i++) {
cin>>a[i];//ai就代表那些数
}
sort(a+1,a+m+1,cmp);
f[0]=0;//恰好装满初始化0
for(int i=1;i<=m;i++) {
for(int j=quantity[a[i]];j<=n;j++) {
f[j]=max(f[j],f[j-quantity[a[i]]]+1);//完全背包转移方程为:f[j]=max(f[j],f[j-v[i]]+w[i]),v[i]所代表的代价,实际就是用去的火柴价值就是让位数加一
}
}
while(n>=0){
for(int i=1;i<=m;i++){//能选m种
if(f[n]==f[n-quantity[a[i]]]+1){//f[总量]=f[总量-火柴代表的量]+1(ai代表的是那种数字,quantity代表这种数字需要的火柴量)
if(n-quantity[a[i]]>=0){//如果不做此判断,会有一些数也满足上个条件,但是减去他就会比总量小出现bug
n-=quantity[a[i]];//总数减去代价
cout<<a[i];
break;
times=i;
}
}
}
if(n-quantity[a[times]]==0){//因为如果做了 if(n-quantity[a[i]]>=0)的判断答案正确但会陷入死循环n永远不会小于0,所以用times记住满足条件的时候是的几个数,然后判断总量减去那个数对应的火柴数是否等于0,是的话就跳出循环
break;
}
}
return 0;
}