回朔法之应用1

Posted zf-blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回朔法之应用1相关的知识,希望对你有一定的参考价值。

题目链接:https://www.nowcoder.com/practice/8fecd3f8ba334add803bf2a06af1b993?tpId=13&tqId=11185&tPage=2&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking

题目描述:

技术分享图片

析:这道题的解空间其实是一个“排列树”,比如输入是{3 , 32 , 321}时,排列树如下:

技术分享图片

所以可以考虑使用回朔法解决。再次回顾一下回朔法的思想:从根节点开始一层一层向下扩展,当扩展到“非扩展节点”时则回溯到上一层,在进行“约束条件”(路径合理性)和“上界条件”(路径最优性,实现剪枝功能)的判断,如果满足则从该节点的另一条路径继续向下,否则继续回溯,就是这样一个递归算法;详细解释可以参考:https://www.cnblogs.com/zf-blog/p/8973051.html

代码如下:

#include<iostream>
#include<string>
#include<vector>
#include<cmath>

using namespace std;

long long min = 0;  //最小数
int n = 0;  //排列树的深度(从0开始)
long long current = 0;  //到达某一节点时的值
vector<long long> x;  //最优解中数组元素的排列

long long m_1(vector<long long> sub, vector<long long> numbers)  //为了计算到达某一节点时的值
{
    int count = 0;
    for (int i = 0; i < numbers.size(); i++)
    {
        long long tmp = numbers[i];
        bool flag = false;  //不包含
        for (int j = 0; j < sub.size(); j++)
        {
            if (tmp == sub[j])
            {
                flag = true;
                break;
            }
        }
        if (flag == false)
        {
            if (numbers[i] == 0)
                count++;
            else
            {
                while (numbers[i] % 10)
                {
                    count++;
                    numbers[i] /= 10;
                }
            }
        }
    }
    return pow(10 , count);
}

void Backtrack(int t)  //回溯算法
{
    if (t >= n)
    {
        current = 0;
        string current_str = "";
        for (int i = 0; i < n; i++)
        {
            string tmp = to_string(x[i]);
            current_str.append(tmp);
        }
        current = atoll(&current_str.at(0));
        if (current < min)
            min = current;
        return;

    }
    for (int i = t; i < n; i++)
    {
        swap(x[t], x[i]);
        vector<long long> tmp;
        for (int j = 0; j <= t; j++)
        {
            tmp.push_back(x[j]);
        }
        long long m_2 = m_1(tmp, x);
        string current_str = "";
        for (int m = 0; m < tmp.size(); m++)
        {
            string tmp_str = to_string(tmp[m]);
            current_str.append(tmp_str);
        }
        current = atoll(&current_str.at(0)) * m_2;
        if (current < min)
        {
            Backtrack(t + 1);
        }
        swap(x[t], x[i]);
    }
}
string PrintMinNumber(vector<long long> numbers) {
    n = numbers.size();
    string min_str = "";
    for (int i = 0; i < n; i++)
    {
        x.push_back(numbers[i]);
        string tmp = to_string(numbers[i]);
        min_str.append(tmp);
    }
    min = atoll(&min_str.at(0));
    Backtrack(0);
    string output = to_string(min);
    return output;
}

int main(int argc, char *argv[])
{
    vector<long long> numbers(3);
    long long a[3] = { 12 , 33 , 4 };
    for (int i = 0; i < 3; i++)
    {
        numbers[i] = a[i];
    }
    string output = PrintMinNumber(numbers);
    cout << output << endl;

    system("pause");
    return 0;
}

 

PS:该算法在VS上验证OK,在牛客网自带的编译器中会出错,属于编译问题;

 

以上是关于回朔法之应用1的主要内容,如果未能解决你的问题,请参考以下文章

回朔法/KMP算法-查找字符串

布线问题(分支限界法)

矩阵中的路径

矩阵中的路径

#构建之法之初体验

构建之法之结对编程