题目:
现在有a根火柴,要求恰好用完这a个火柴摆出数位为n的数字,并要求这个数字最大,或者判断没有数字能满足条件。
数字0需要6根火柴。
数字1需要2根火柴。
数字2需要5根火柴。
数字3需要5根火柴。
数字4需要4根火柴。
数字5需要5根火柴。
数字6需要6根火柴。
数字7需要3根火柴。
数字8需要7根火柴。
数字9需要6根火柴。
输入格式
第一行一个整数T(1 <= T <= 100),表示接下来有T个测试输入。
接下来T行,每行两个整数a,n(1 <= a,n <= 200),涵义如上表示。
输出格式
输出T行数字,分别表示依次表示T个测试的答案。
对于每个测试的答案,若存在满足条件的数字则将其输出,否则输出-1。
输入样例
5
5 1
6 1
5 2
6 2
5 3
输出样例
5
9
71
77
-1
Hint
(1)数位为n的数字指的是由n个数字组成的数字,如123,其数位为3。
(2)本题有许多做法,可以多想想哦。
个人想法:第一眼看题,光空想觉得jio得用,贪心+回溯就可以轻松ac了,跟找硬币问题很像。
不过遗憾的是回溯学了两周还是不会写,然后就打草稿看看能不能简化问题。
要使数字尽可能大,发现“6,3,2”是没用的,因为有与它们火柴花费一样而数值更大的数字。
思路:所谓贪心,就让每一步的尽可能最优,所以每次都要尽可能取最大数,若不满足就换下一个小一点数字?想法很好,感觉要用回溯,但如果能提前判断下一步的可行性就不用回溯了。
发现可选的数字的火柴花费在2~7之间,并且每个数字都能取到,自然可得n位数的火柴数目为2n到7n。
利用这个限制条件,就可以提前判断下一步的可行性了。
#include<iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
int num[]={9,8,7,5,4,1};//将数字按照从大到小存入数组
int match[]={6,7,3,5,4,2};//每个数字对应花费的火柴数目
int result[205];//记录最后结果
int main()
{
int a,n,i,j=0;
int T;
cin>>T;
while(T--)
{
j=0;//初始化变量,(每次提交都死在初始化上面 )
memset(result,0,sizeof(result));
cin>>a>>n;//输入
if(a<2*n||a>7*n) {cout<<"-1"<<endl;continue;} //先排除不满足的特殊情况
int m=n,p=n;
while(n--)
{
for(i=0;i<6;i++)
{
if(a-match[i]>7*(m-1)) continue;//目前火柴数目-下一步花费的火柴是否在2n~7n之间
else if(a-match[i]<2*(m-1)) continue;
else {a-=match[i];result[j]=num[i];j++;break;}//若满足则记录下来
}
m--;
}
for(i=j-p;i<j;i++) cout<<result[i];//输出,因为有可能有前导0,所以要按位数n输出,因为n改变了,所以设置一个p记录原来n值
cout<<endl;
}
return 0;
}