`

带重复数字的全排列

J# 
阅读更多
上次gx同学问我一道又重复数字的全排列的问题,我当时用set保存,然后直接回溯。这这种做法,效率比较低,没有去剪枝,从而像1,1,1,1,1这样的序列都需要回溯很多次。今天写了一个剪枝的。

public class Permutation
{
    private int[] a;
    
    public Permutation(int[] a)
    {
        this.a = a;
    }
    public  boolean isOk(int b,int e){//判断是否重复
        if(b < e){
            for(int i = b; i < e; i++){
                if(a[i] == a[e])
                    return false;
            }
        }
        return true;
    }
    
    public void permutation(int k){
        if(k >= a.length){
            print();
        }else{
            for(int i = k; i < a.length; i++){
                if(isOk(k,i)){
                    swap(i,k);
                    permutation( k+1 );
                    swap(i,k);
                }
            }
        }
        
    }
    
    private void swap( int i, int k )
    {
        int temp = a[i];
        a[i] = a[k];
        a[k] = temp;
    }
    
    private void print()
    {
        for( int i = 0; i < a.length; i++ )
        {
            System.out.print(a[i] + " ");
        }
        System.out.println();
    }
    
    public static void main( String[] args )
    {
        Permutation p = new Permutation(new int[]{1,2,2,2});
        p.permutation( 0 );
    }
}


c++ STL algorithm中有next_permutation可以直接调用,ACM的时候经常偷懒用这个,呵呵。
学以致用:poj 1731
http://acm.pku.edu.cn/JudgeOnline/problem?id=1731
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;

string goods;
vector<string> v;

void swap(string &str,int i, int j){
	char temp = str[i];
	str[i] = str[j];
	str[j] = temp;
}

bool ok(int i, int j){
	if( i < j){
		for(int k = i; k < j; k++){
			if(goods[k] == goods[j])
				return false;
		}
	}
	return true;
}
void backtrack(int i){
	if(i >= goods.length()){
		 v.push_back(goods);
	}
	
	for(int j = i; j < goods.length(); j++){
		if(ok(i,j)){
			swap(goods,i,j);
			backtrack(i + 1);
			swap(goods,i,j);
		}
	}
}

int main(){
	cin >> goods;
	backtrack(0);
	sort(v.begin(),v.end());
	for(int i = 0; i < v.size(); i++){
		cout << v[i] << endl;
	}
}

poj1256 http://acm.pku.edu.cn/JudgeOnline/problem?id=1256
这道题需要一种特殊的数序输出:
An upper case letter goes before the corresponding lower case letter.
So the right order of letters is 'A'<'a'<'B'<'b'<...<'Z'<'z'.
我们只需要定义一个正确的比较函数就可以了
bool cmp(const string &str1,const string &str2){  
    int i;  
    int m_len = min(str1.length(), str2.length());  
    for(i = 0; i < m_len; i++){  
        if(str1[i] != str2[i])  
            break;  
    }  
  
    if(i == m_len){  
        return str1.length() < str2.length();  
    }else if(tolower(str1[i]) == tolower(str2[i])) {  
        return str1[i] < str2[i];  
    }else{  
        return tolower(str1[i]) < tolower(str2[i]);  
    }  
}  

或者
bool cmp(char c1,char c2){
	if(tolower(c1) == tolower(c2)) 
		return c1 < c2;
	else
		return tolower(c1) < tolower(c2);
}

这样我们的代码就出来了:
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;

string str;
vector<string> permutations;

bool cmp(const string &str1,const string &str2){
	int i;
	int m_len = min(str1.length(), str2.length());
	for(i = 0; i < m_len; i++){
		if(str1[i] != str2[i])
			break;
	}

	if(i == m_len){
		return str1.length() < str2.length();
	}else if(tolower(str1[i]) == tolower(str2[i])) {
		return str1[i] < str2[i];
	}else{
		return tolower(str1[i]) < tolower(str2[i]);
	}
}

void swap(int i,int j){
	char temp = str[i];
	str[i] = str[j];
	str[j] = temp;
}

bool isOk(int i,int j){
	if(i < j){
		int k;
		for(k = i; k < j; k++){
			if(str[k] == str[j])
				return false;
		}
	}
	return true;
}

void backtrack(int i){
	if( i >= str.length()){
		permutations.push_back(str);
		return;
	}

	int j;
	for(j = i; j < str.length(); j++){
		if(isOk(i,j)){
			swap(i,j);
			backtrack(i+1);
			swap(i,j);
		}
	}
}

int main(){
	int n;
	cin >> n;
	int i,j;
	for(i = 0; i < n; i++){
		cin >> str;
		permutations.clear();
		backtrack(0);
		sort(permutations.begin(),permutations.end(),cmp);
		for(j = 0; j < permutations.size(); j++){
			cout << permutations[j] << endl;
		}
	}
}

我们还是用STL来爽爽这道题吧:
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;

string str;

bool cmp(char c1,char c2){
	if(tolower(c1) == tolower(c2)) 
		return c1 < c2;
	else
		return tolower(c1) < tolower(c2);
}

int main(){
	int n;
	cin >> n;
	int i,j;
	for(i = 0; i < n; i++){
		cin >> str;
		sort(str.begin(),str.end(),cmp);
		cout << str << endl;
		while(next_permutation(str.begin(),str.end(),cmp)){
			cout << str << endl;
		}
	}
	return 0;
}
1
0
分享到:
评论

相关推荐

    C语言重复数全排列的代码

    生成这些字符的不重复的全排列,并将结果打印到标准输出上。 【输入形式】 从标准输入上读入一个由字母、数字组成的字符串,字符串的长度小于100,其中包含重复的字符。 【输出形式】 向标准输出印...

    有重复数字的全排列代码

    算法分析课程作业,C语言编写,可能需要用input.txt输入,有重复数字的全排列代码

    C#实现解决全排列重复问题

    当输入元素中存在重复时,处理全排列问题会变得更为复杂。C#作为.NET框架下的主要编程语言,提供了丰富的数据结构和算法支持来解决这类问题。本篇文章将深入探讨如何使用C#解决全排列重复问题,并提供一种有效的实现...

    输出n个数字的全排列(可重复)

    1、输入n个数(不重复),求n个数字的全排列 如:n=3 全排列的数字为 1 2 3 则输出 123 132 213 231 321 312 2、输入n和k(n》=k)求n个数字的(n,k)排列 如n=3,k=2 输入的三个数位1 2 3 则输出 12 13 21 23 31...

    使用swap函数求解带有重复字符串的全排列

    这样我们也得到了在全排列中去掉重复的规则——去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。用编程的话描述就是第i个数与第j个数交换时,要求[i,j)中没有与第j个数相等的数。下面给出...

    回溯法 - 输出自然数1到n所有不重复的排列,即n的全排列

    根据给定文件的信息,本文将深入探讨如何使用回溯法来输出自然数1到n的所有不重复排列(即n的全排列)。同时,还将提供一个Java实现的具体示例。 ### 回溯法简介 回溯法是一种通过尝试解决离散和组合问题的方法,...

    易语言源码易语言数字文本的全排列.rar

    5. 为了防止重复排列,通常需要一个辅助数组或集合来跟踪已使用的数字,确保每次选择的数字都是未被使用过的。 在实际的易语言代码中,你可能会看到类似`整数数组`、`循环`、`递归调用`等关键字和结构。此外,为了...

    去重全排列的递归实现

    去重全排列的递归实现 去掉重复数字的 全排列的 递归实现

    易语言数字文本的全排列

    在编程领域,全排列是一种常见的算法问题,它涉及到对一组数据进行所有可能的无重复、无顺序的排列。在这个特定的场景中,我们关注的是如何使用易语言来实现数字文本的全排列。易语言是中国本土开发的一种编程语言,...

    使用swap求解不重复字符串的全排列

    为方便起见,用123来示例下。123的全排列有123、132、213、231、312、321这六种。...因此可以知道——全排列就是从第一个数字起每个数分别与它后面的数字交换。找到这个规律后,递归的代码就很容易写出来了:

    用回溯法求序列的全排列

    回溯法的优点在于可以避免重复计算,只需要在每个分支上尝试所有可能的选择,直到找到解决方案或者确定无解。缺点是效率通常低于动态规划等其他算法,因为它可能涉及到大量的回溯操作。然而,对于小规模的问题,如本...

    局部搜索解决全排列问题

    此外,对于包含重复数字的排列,使用递归方法会产生重复的排列组合,因为在生成新排列时不便于与已生成的排列进行比较。为避免重复,需要更高效的存储和检查机制,这超出了简单的递归解决方案的能力范围。 解决矩阵...

    易语言数字文本的全排列.7z

    这里我们讨论的是使用易语言实现数字文本的全排列。易语言是一种中文编程语言,它以简单易懂的语法设计为特点,使得初学者也能快速上手。 全排列是指从n个不同元素中取出m(m≤n)个元素,按照一定的顺序排成一列,...

    题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

    每层循环从1到4,确保不会重复使用同一个数字。`for(i=1;i;i++)`、`for(j=1;j;j++)`、`for(k=1;k;k++)`就是这个三重循环的表示。 2. **条件判断**: - `if (i!=k&&i!=j&&j!=k)` 这个条件判断确保了生成的三位数的...

    全排列-非递归算法

    初始状态下,容器为空,然后依次将数字1到6添加到容器中,每次添加时,确保新添加的数字不与容器内已有数字重复。 以下是实现该算法的基本步骤: 1. 初始化一个空容器,用于存储排列。 2. 对于每个待排列的数字,...

    c程序100例 题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

    在C#编程中,我们经常会遇到需要解决排列组合问题,比如本题所示的例子:如何用1、2、3、4这四个数字组成互不相同且无重复数字的三位数,并计算总数以及列举出所有可能的组合。这个问题属于组合数学中的全排列问题,...

    全排列算法解析(完整版)

    递增进位制数法和递减进位制数法是实现全排列的另外两种方法,它们将排列的构造类比为数字的进位过程,通过改变“进位”位置来生成新的排列。邻位对换法则是一种更直观的排列生成方法,通过交换排列中的相邻元素来...

    全排列的生成算法

    全排列的生成算法是指对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。任何 n 个字符集的排列都可以与 1~n 的 n 个数字的排列一一对应,因此在此就以 n 个数字的排列为例说明排列的生成...

    Java实现字符数组全排列的方法

    在实际编程中,全排列的算法不仅适用于字符数组,还可以应用于数字数组或其他可比较类型的数组,为解决各种排列组合问题提供基础。理解并掌握这种算法,对于提升Java编程能力,特别是在处理复杂问题时,是非常有帮助...

Global site tag (gtag.js) - Google Analytics