暴力と振り返り

1. 1〜nの順列を生成します

#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//使用普通数组实现
void print_permutation(int n, int *A, int cur, int &cnt){ //由于无法知道数组的元素个数,用cur进行保存
    if(cur == n){
        cnt++;
        for(int i = 0; i < n; i++)printf("%d", A[i]);
        printf("\n");
    }else{
        for(int i = 1; i <= n; i++){
            bool flag = true;
            for(int j = 0; j < cur; j++){
                if(A[j] == i){flag = false; break;}     //不能选择里面已经有的数字
            }
            if(flag){
                A[cur] = i;
                print_permutation(n, A, cur+1, cnt);         //递归调用
            }
        }
    }
}

//使用vector容器实现
void print_permutation2(int n, vector<int>A, int &cnt){
    if((int)A.size() == n){
        cnt++;
        for(int i = 0; i < n; i++)printf("%d", A[i]);
        printf("\n");
    }else{
        for(int i = 1; i <= n; i++){
            vector<int>::iterator iter=find(A.begin(),A.end(),i);
            if(iter == A.end()){
                A.push_back(i);
                print_permutation2(n, A, cnt);
                A.erase(A.end() - 1);
            }
        }
    }
}

int main(){
    int n = 6, A[10], cnt = 0;
    vector<int>B;
    printf("使用普通数组实现\n\n\n");
    print_permutation(n, A, 0, cnt);
    printf("\n");
    printf("使用vector实现\n\n");
    cnt  = 0;
    print_permutation2(n, B, cnt);
    printf("共计%d个\n", cnt);
}
  1. 繰り返し可能な順列を生成する
void print_permutationR(int n, int *A, int cur, int &cnt, int *P){
    if(cur == n){
        cnt++;
        for(int i = 0; i < n; i++)printf("%d", A[i]);
        printf("\n");
    }else{
        for(int i = 0; i < n; i++){
            int c1 = 0, c2 = 0;
            for(int j = 0; j < cur; j++)if(A[j] == P[i]) c1++;
            for(int j = 0; j < n; j++)if(P[i] == P[j]) if(!i || P[i] != P[i-1]) c2++;//不重复不遗漏取遍P的值
            if(c1 < c2){
                A[cur] = P[i];
                print_permutationR(n, A, cur+1, cnt, P);
            }
        }
    }
}

3.サブセット生成
方法1:インクリメンタル構築方法

void print_subset3(int n, int *A, int cur, int num[]){
    printf("[ ");
    for(int i = 0; i < cur; i++){
        printf("%d ", num[A[i]]);
    }
    printf("]\n");
    int s = cur ? A[cur-1]+1 : 0;
    for(int i = s; i < n; i++){
        A[cur] = i;
        print_subset3(n, A, cur+1, num);
    }
}
int main(){
    int n = 3, A[10], P[3] = {1, 2, 3};
    vector<int>B;
    printf("使用增量构造法:\n");
    print_subset3(n, A, 0, P);
}

方法2:ビットベクトル法を使用する

void print_subset2(int n, int *B, int cur, int num[]){
    if(cur == n){
        printf("[ ");
        for(int i = 0; i < cur; i++){
            if(B[i])printf("%d ", num[i]);
        }
        printf("]\n");
        return ;
    }
    B[cur] = 1;                             //选择cur;
    print_subset2(n, B, cur+1, num);
    B[cur] = 0;                             //不选cur;
    print_subset2(n, B, cur+1, num);

}
int main(){
    int n = 3, A[10], P[3] = {1, 2, 3};
    printf("使用位向量法:\n");
    print_subset2(n, A, 0, P);
}

方法3、バイナリメソッドを使用し
ます。1。サブセットを記述します。バイナリビットを使用して、サブセットの特定の要素が存在するかどうかを示します。
このように、フルセットは(1 << n)-1で表すことができ、サブセットは[0、1 << n-1]の数です。

2.出力セット:バイナリANDが使用されます。(s&(1 << i))がサブセットのi番目のビットが存在することを示している場合、出力されます。


void print_subset(int n, int s, int num[]){
    printf("[ ");
    for(int i = 0; i < n; i++){
        if(s&(1<<i))printf("%d ", num[i]);
    }
    printf("]\n");
}
void get_subset(int n, int num[]){
    for(int i = 0; i < (1<<n); i++){
        print_subset(n, i, num);
    }
}
int main(){
	int P[3] = {1, 1, 3};
    printf("子集为:\n");
    get_subset(3, P);
}

1.バックトラックの例

おすすめ

転載: blog.csdn.net/fuzekun/article/details/113443026