全排列
1,热身一下:
列出从n个数取出r个数的情况,取出的r个数以字典序最小的方式出现。
c++:
#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int n = 6, r = 3, data[4], flag[4] = {0};
//data:取出的r个数(1~3) flag:标记是否被取
void out(){ //输出得到的data数组
for(int i=1;i<=r;i++){
cout<<data[i]<<" ";
}
cout<<endl;
}
void done(int i){
for(int j=data[i-1]+1;j<=n;j++){
if(flag[j]==0){ //未取
data[i] = j; //该数未取则赋值于data[i]中
flag[j] = 1; //已取则标记为1
if(i==r){
out(); //取到r个数则输出
}else{ //递归
done(i+1); //递归取下一个数
}
flag[j] = 0; //递归回溯
}
}
}
int main(int argc, char** argv) {
data[0] = 0;
done(1);
return 0;
}
输出效果:
1 2 3
1 2 4
1 2 5
1 2 6
1 3 4
1 3 5
1 3 6
1 4 5
1 4 6
1 5 6
2 3 4
2 3 5
2 3 6
2 4 5
2 4 6
2 5 6
3 4 5
3 4 6
3 5 6
4 5 6
2,例题
购票问题
一个浏览区的门票是50元,有2n位人参加排列买票,其中n个人手里拿100元,n个人手里拿50元,售票处没有多余的钱,问不出现找不开钱的排队方式有多少种。
搜索策略:
指定一个变量k记录售票处有50元钞票的张数,初始时令k=0,若某人手持100元钞票且k=0时则回溯,否则继续递归。若2n人都购完票,则计数器加1。递归结束后,计算器中的值就是排队方案数。
c++:
#include <iostream>
using namespace std;
#include <stdio.h>
#define N 3
int m=0,k=0;
int n = N;
__int64 total=0;
int main()
{
void out();
void dfs(int i);
dfs(1);
out();
return 0;
}
void dfs(int i)
{
int j;
for(j=0;j<=1;j++)
{
if(j==0)
{
k++;
m++;
if(m==n)
{
total++;
}else
{
dfs(i+1);
}
k--;
m--;
}else
{
if(k>0)
{
k--;
dfs(i+1);
k++;
}
}
}
}
void out()
{
printf("%d ",total);
}
输出结果:5
3,poj1256
Anagram
Description
You are to write a program that has to generate all possible words from a given set of letters.
Example: Given the word “abc”, your program should - by exploring all different combination of the three letters - output the words “abc”, “acb”, “bac”, “bca”, “cab” and “cba”.
In the word taken from the input file, some letters may appear more than once. For a given word, your program should not produce the same word more than once, and the words should be output in alphabetically ascending order.
(你要写一个程序,它必须从一组给定的字母中生成所有可能的单词。
示例:给定单词“abc”,您的程序应该——通过探索这三个字母的所有不同组合——输出单词“abc”、“acb”、“bac”、“bca”、“cab”和“cba”。
在从输入文件中取出的单词中,有些字母可能出现不止一次。对于给定的单词,您的程序不应该不止一次地产生同一个单词,并且这些单词应该按字母升序输出。)
Input
The input consists of several words. The first line contains a number giving the number of words to follow. Each following line contains one word. A word consists of uppercase or lowercase letters from A to Z. Uppercase and lowercase letters are to be considered different. The length of each word is less than 13.(输入由几个单词组成。第一行包含一个数字,表示接下来的单词数。下面的每一行包含一个单词。单词由A ~ z中的大写字母或小写字母组成,大写字母和小写字母不同。每个单词的长度小于13。)
Output
For each word in the input, the output should contain all different words that can be generated with the letters of the given word. The words generated from the same input word should be output in alphabetically ascending order. An upper case letter goes before the corresponding lower case letter.(对于输入中的每个单词,输出应该包含可以用给定单词的字母生成的所有不同单词。由相同输入单词生成的单词应按字母升序输出。大写字母在对应的小写字母之前。)
Sample Input
3
aAb
abc
acba
Sample Output
Aab
Aba
aAb
abA
bAa
baA
abc
acb
bac
bca
cab
cba
aabc
aacb
abac
abca
acab
acba
baac
baca
bcaa
caab
caba
cbaa
第一次尝试:
c++:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
string s;
int n;
set<string> c;
bool cmp(char a, char b){
return a<b;
}
void out(vector<int> a){
if(!a.empty()){
string ss = "";
for(int i=0;i<a.size();i++){
ss = ss+s[a[i]]+"";
}
if(c.count(ss)==0){
cout<<ss<<endl;
c.insert(ss);
}
}
}
int main(int argc, char** argv) {
int m;
cin>>n;
while(n--){
cin>>s;
m = s.length();
sort(s.begin(),s.end(),cmp);
vector<int> a;
for(int i=0;i<m;i++){
a.push_back(i);
}
out(a);
while(a.size()!=0){
int t = a[a.size()-1];
a.erase(a.begin()+a.size()-1);
int j = 0;
for(j=t+1;j<m;j++){
if(find(a.begin(),a.end(),j)==a.end()){
a.push_back(j);
for(int i=0;i<m;i++){
if(count(a.begin(),a.end(),i)==0){
a.push_back(i);
}
}
out(a);
break;
}
}
}
}
return 0;
}
看了大佬的代码,明白原来是排序错了
正确代码:
c++:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
char ss[100]; //原字符串
char str[100]; //新组合后的字符串
bool flag[100] = {0}; //标记数组
int m; //字符串的长度
int cmp(char a, char b){ //排序
char ch1 = a;
char ch2 = b;
if(ch1>='A'&&ch1<='Z'){
ch1 = (char)(ch1+32);
}
if(ch2>='A'&&ch2<='Z'){
ch2 = (char)(ch2+32);
}
if(ch1!=ch2)
return ch1<ch2;
return a<b;
}
void find(int i){
if(i==m){
for(int j=0;j<m;j++){ //输出得到的字符数组
cout<<str[j];
}
cout<<endl;
return;
}
for(int j=0;j<m;j++){
if(!flag[j]){ //该点未被访问
if(j>0&&!flag[j-1]&&ss[j]==ss[j-1])
continue; //防止排序得到的字符串重复
flag[j] = 1; //该点被访问,标记为1
str[i] = ss[j]; //赋值
find(i+1); //递归为下一个字符赋值
flag[j] = 0; //递归回溯
}
}
}
int main(int argc, char** argv) {
int n;
cin>>n;
while(n--){
cin>>ss;
m = strlen(ss);
sort(ss,ss+m,cmp);
find(0);
}
return 0;
}
简短代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int cmp(char a, char b){ //排序
char ch1 = a;
char ch2 = b;
if(ch1>='A'&&ch1<='Z'){
ch1 = (char)(ch1+32);
}
if(ch2>='A'&&ch2<='Z'){
ch2 = (char)(ch2+32);
}
if(ch1!=ch2)
return ch1<ch2;
return a<b;
}
int main(int argc, char** argv) {
int n;
cin>>n;
while(n--){
char ss[100];
cin>>ss;
int m = strlen(ss);
sort(ss,ss+m,cmp);
cout<<ss<<endl;
while(next_permutation(ss,ss+m,cmp)){
cout<<ss<<endl;
}
}
return 0;
}