1、题目大意

题目描述

Froggy 分别给出 10 个数码的出现次数,你需要找到一个由这些数码组成的最小的数,满足:
1. 这个数是回文的。
2. 不能有前导 0。
注:假设这个数字长度是 L,那么这个数是回文的当且仅当对于任意的 i∈[1,L],第 i 位的数码和第 L−i+1 位的数码相同。
快来帮帮 Froggy 吧!

输入描述:

一行 10 个自然数,分别表示数码0∼9的出现次数。

输出描述:

		
如果无解,只输出 “-1”。(不含引号)
否则,输出一个数表示最小的解。

2、问题分析以及代码求解

回文数该类问题也遇到了很多,一般使用string类进行维护。
思路如下:1、首先考虑不能输出回文数而是输出-1的情况:
总共两种:第一是具有前导0;
第二有2种小情况:①0~9中某一个数的个数是奇数个,这时需要满足0~9所有数的个数为奇数个,否则无法生成回文数。
②0~9中有超过1种数的个数为奇数个,此时一定无法生成回文数。
2、其他情况均能生成回文数,根据回文数的特点,只需要维护前半部分的数据,后半部分数据通过逆序进行输出。
3、维护数据时,直接从0~9开始维护,即使有0的存在,仍按照0~9的顺序进行维护。
4、后续判断是否有前导0的存在,若有前导0的存在,暴力搜索是否还有其他数字参与维护回文数,若有,交换两者的位置即可。
5、输出时判断是否是前导0,若是输出-1;否则先正序输出,接着逆序输出。不过需要一个注意点:若0~9的总个数为奇数个的时候,需要定义一个变量维护个数为奇数的值,后续在输出时输出一次即可。
#include <bits/stdc++.h>
using namespace std;

int a[10],sum,is;
int dex = 11;
string s;
bool have0;
int main()
{
    for (int i = 0;i < 10;i++){
        scanf("%d",&a[i]);
        sum += a[i];
        if (a[i] % 2 == 1) is++,dex = min(dex,i);
    }
    if ((sum % 2 == 0 && is != 0) || (sum % 2 == 1 && is != 1)){
        cout << -1;
        return 0;
    }
    for (char i = 0;i <= 9;i++)
        for (int j = 1;j <= a[i] / 2;j++) s += (i + '0');
    if (s[0] == '0')
        for (int i = 1;i < s.length();i++)
            if (s[i] != '0'){
                swap(s[0],s[i]);
                break;
            }
    if (s[0] == '0') cout << -1;
    else{
        for (int i = 0;i < s.length();i++) cout << s[i];
        if (sum % 2 == 1) cout << dex;
        for (int i = s.length() - 1;i >= 0;i--) cout << s[i];
    }
    
    return 0;
}

3、芝士链接

贪心、模拟、思维

4、洞见总结

遇到回文数该类题型时,一般采取string类维护数据,然后根据题目要求转变为对字符串操作。