SCAU 2020新生赛E题

题目:
现在有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;
}
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值