https://oomake.com/question/1736140点击查看更多大佬

题意:
n根火柴,能摆出的最大数和最小数,没有前导零。
思路:
最大数很简单,n是偶数就“111”,是奇数就"711",位数尽可能大。
最小数位数要尽可能小,如果n是7的倍数,全摆成‘8’是最优的;如果不是,那我们要让当前摆的值尽可能小,这句话不好理解,一般你看懂代码才能明白,接下来我会用更简单的思路来让你理解这种解法。
思路详解:

假如我们有n根火柴,要摆出最小的数,我们会先摆‘8’,消耗尽可能多的火柴,会出现多{0,1,2,3,4,5,6}根火柴的情况,多0已经是最优解,不必理会;多1,我们拆‘8’,n>=2不会出现给你1根的情况,我们一定有‘8’拆,把‘8’拆成‘0’,组合成‘10’是最优的;多2,最优解‘18’;多3,继续拆‘8’得‘0’,如果‘8’拆成‘0’还不够怎么办?这个就需要你自己算一下只摆两位数时的最优解了(如上图),我们现在要摆‘2’,可以注意到多4多5也是优先摆‘2’,多6就要优先摆‘6’,最终大体上的方向就是‘8’完‘0’变,不够就往最优拆。
然后,我们思考一下,这个思路有没有问题?我们还要考虑没‘8’拆的情况,也就是一位数(n<=7),我们应该再深入模拟一下,因为我们并不知道这样的思路能不能保证位数最低,答案应该是什么样子的?‘888’;‘x888’;‘x08’;‘x00’;‘100’;‘108’。。。是不是最优解和‘0’‘8’的组合。我们记录剩下的火柴数,如果‘8’刚好用光,最优;如果剩1,2,先摆‘1’,剩下的火柴不能全‘8’的话就‘0’,就是‘8’拆成‘0’,不会有很奇怪的情况;如果剩3,4,5,先摆‘2’,剩下的不能全‘8’就摆‘0’,同上,觉得奇怪就代一下,最后一位判断一下;剩‘6’同上。废话有点多,之后如果能想的更清晰,再来更新一下,具体看代码理解。
#include <bits/stdc++.h>
#define insert_num(x) {v.push_back(x+'0');num_flag=x;}
using namespace std;
int main(int argc, char const *argv[])
{
int t,n;
scanf("%d",&t);
int min_num[]={8,-1,1,7,4,2,6,8};
int val[]={6,2,5,5,4,5,6,3,7,6};
vector<char> v,v0;
while(t--)
{
scanf("%d",&n);
int a=n;
int flag=1,num_flag;
int c=ceil(a/7.);//注意用double型
v.clear();
v0.clear();
while(c)
{
if(c==1)
{
int tmp=min_num[a];
if(!flag&&a==6) tmp=0;
insert_num(tmp)
}
else if(a%7==0)
{
v.insert(v.end(),c,'8');
break;
}
else
{
if(flag)
{
if(a%7<=2) insert_num(1)
else if(a%7<6) insert_num(2)
else if(a%7==6) insert_num(6)
}
else
insert_num(0);
}
a=a-val[num_flag];
c=ceil(a/7.);
flag=0;
}
if(n%2)
{
v0.push_back('7');
v0.insert(v0.end(),(n-3)/2,'1');
}
else v0.insert(v0.end(),n/2,'1');
string min_s=string(v.begin(),v.end());
string max_s=string(v0.begin(),v0.end());
cout<<min_s<<" "<<max_s<<endl;
}
return 0;
}
这篇博客探讨了如何使用n根火柴棒构建最大的和最小的数字,无前导零。最大数的构造相对直观,而最小数的构建则需要更复杂的策略。当n为7的倍数时,全摆成'8'是最优解,否则需要通过拆分和组合寻找最小位数。博主提供了详细思路,包括如何处理火柴棒剩余的情况,并建议通过代码实现来更好地理解该问题。
4775

被折叠的 条评论
为什么被折叠?



