基于交换的全排列递归解法(去重+有序)poj1256

目录

问题描述

输入

输出

解题思路

AC代码

我写的最简洁的代码(用sort进行比较):

不用sort函数自己排序的代码:

用字符数组AC的代码


问题描述

你要编写一个程序,该程序必须从一组给定的字母中生成所有可能的单词。
示例:给定单词“abc”,您的程序应该通过探索三个字母的所有不同组合来输出单词“abc”、“acb”、“bac”、“bca”、“cab”和“cba”。
在从输入文件中获取的单词中,某些字母可能会多次出现。对于给定的单词,程序不应多次生成相同的单词,并且单词应按字母升序输出。

输入

输入由几个单词组成。第一行包含一个数字,给出要遵循的单词数。以下每行包含一个单词。单词由从 A 到 Z 的大写或小写字母组成,大写和小写字母被视为不同。每个单词的长度小于 13。

输出

对于输入中的每个单词,输出应包含可以使用给定单词的字母生成的所有不同单词。从同一输入词生成的单词应按字母升序输出。大写字母位于相应的小写字母之前。

解题思路

考虑到输入的序列可能无序,首先给输入序列排序。通过给每个可能的字母一个唯一的序列号实现。当然,也可以写一个cmp函数用sort函数排序,更简单。这不是重点,咱们还是把目光主要放在permutation里吧。

然后用递归实现排列。第i层给出第i个字母的可能取值。为了防止重复输出,需要在每层循环时加一个判断条件:如果这个字母在之前已经排列过,就跳过它。为了保证输出的有序性,不用回溯,回溯会破坏有序性。比如:第一个字母排完后,让他和第二个字母交换位置,这样第三个字母交换时就会跟原来的第二个字母进行交换。但是需要注意:每i层递归退出时应该保证退出时的序列顺序与进入时的序列相同,否则将导致上一层继续递归的序列与一开始给的序列不符。比如:排序abc:abc,acb当在运行下一步时,应该排序bac,但会排成cab。递归主要关注的就是两个地方:一个是当前层,一个是当前层与更小层的关联。交换会导致当前层能遍历到所有的给定的字母,且不影响下一层遍历所有字母,每一层返回时应把序列返回到进入时的状态,不然就会影响上一层的遍历。因为在c++中string是值传入,所以这一步可以不用反应到代码当中。但如果用数组,就必须在代码当中体现。因为数组是引用传递。permutaton的m是当前层,n是最多能到达的层数,即到第n层所有字母都被选取了,就该输出啦。

AC代码

我写的最简洁的代码(用sort进行比较):

#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
void swap(string &s, int a, int b)
{
    char t = s[a];
    s[a] = s[b];
    s[b] = t;
}
bool cmp(char a, char b)
{
    double aa = a;
    double bb = b;
    double d = 'a' - 'A' - 0.5;
    if (aa >= 'a')
    {
        aa = a - d;
    }
    if (bb >= 'a')
    {
        bb = b - d;
    }
    return aa < bb;
}
void permutation(string s, int m, int n)
{
    if (m == n)
    {
        cout << s;
        cout << endl;
    }
    else
    {
        for (int i = m; i <= n; i++)
        {
            if (i != m && s[i] == s[m])
            {
                continue;
            }
            swap(s, i, m);
            permutation(s, m + 1, n);
        }
    }
}
int main(int argc, char const *argv[])
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
    {

        string str;
        cin >> str;
        sort(str.begin(), str.end(), cmp);
        permutation(str, 0, str.size() - 1);
    }
    return 0;
}

不用sort函数自己排序的代码:

#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
struct word
{
    int order;
    char name;
};
void swap(string &s, int a, int b)
{
    char t = s[a];
    s[a] = s[b];
    s[b] = t;
}
void permutation(string s, int m, int n)
{
    if (m == n)
    {
        cout << s;
        cout << endl;
    }
    else
    {
        for (int i = m; i <= n; i++)
        {
            if (i != m && s[i] == s[m])
            {
                continue;
            }
            swap(s, i, m);
            permutation(s, m + 1, n);
        }
    }
}
int main(int argc, char const *argv[])
{
    // freopen("../luogu/text.in", "r", stdin);
    word w[26 * 2];
    for (int i = 0, j = -1; i < 26 * 2; i++)
    {
        w[i].order = i;
        if (i % 2 == 0)
        {
            j++;
            w[i].name = 'A' + j;
        }
        else
            w[i].name = 'a' + j;
    }
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
    {

        string str;
        cin >> str;
        vector<word> b; // 待排列的数组
        for (int j = 0; j < str.size(); j++)
        {
            int a = 0;
            // 找到该字母的order
            for (int k = 0; k < 26 * 2; k++)
            {
                if (w[k].name == str[j])
                {
                    a = w[k].order;
                    break;
                }
            }
            word c; // 待插入的数
            c.name = str[j];
            c.order = a;
            if (b.size() == 0)
            {
                b.push_back(c);
            }
            else
            {
                int p = 0;
                while (p < b.size() && b[p].order < a)
                {
                    p++;
                }
                if (p == b.size())
                {
                    b.push_back(c);
                }
                else
                    b.insert(b.begin() + p, c);
            }
        }
        string s;
        for (int j = 0; j < b.size(); j++)
        {
            s.push_back(b[j].name);
        }
        permutation(s, 0, s.size() - 1);
    }
    return 0;
}

用字符数组AC的代码

通过学习别人的博客,我发现如果传进去数组,应该这样写permutation函数

#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
bool cmp(char a, char b)
{
    double aa = a;
    double bb = b;
    double d = 'a' - 'A' - 0.5;
    if (aa >= 'a')
    {
        aa = a - d;
    }
    if (bb >= 'a')
    {
        bb = b - d;
    }
    return aa < bb;
}
void swap(char *s, int a, int b)
{
    int t = s[a];
    s[a] = s[b];
    s[b] = t;
}
void mycopy(char *a, char *b, int size)
{
    for (int j = 0; j < size; j++)
    {
        a[j] = b[j];
    }
}
void permutation(char *s, int m, int n)
{
    if (m == n)
    {
        printf("%s\n", s);
    }
    else
    {
        char t[100];
        for (int i = m; i < n + 1; i++)
        {
            if (i == m)
            {
                mycopy(t, s, n + 1);
            }
// 注意此处需要特判一个特殊情况,即下面的if语句。因为第二个if语句的continue可能导致之后的代码不执行而出现问题(无法回溯)
            if (i == n && i != m && s[i] == s[m])
            {
                mycopy(s, t, n + 1);
                continue;
            }
            if (i != m && s[i] == s[m])
            {
                continue;
            }
            swap(s, i, m);
            permutation(s, m + 1, n);
            if (i == n)
            {
                mycopy(s, t, n + 1);
            }
        }
    }
}
int main(int argc, char const *argv[])
{
    int n;
    cin >> n;
    while (n--)
    {
        char s[100];
        cin >> s;
        int lenth = strlen(s);
        sort(s, s + lenth, cmp);
        permutation(s, 0, lenth - 1);
    }

    return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值