1. 程式人生 > >dfs 全排列演算法(含重複元素)

dfs 全排列演算法(含重複元素)

1、數的全排列

求數字 1 ~ n 的全排列,例如 1~3 的全排列,輸出 1 2 3, 1 3 2 , 2 1 3, 2 3 1, 3 1 2, 3 2 1

#include<bits/stdc++.h>
using namespace std;

#define runfile freopen("E:/Code/CB/Root/data.txt", "r", stdin)
#define stopfile fclose(stdin)

const int maxn = 100;
int n,vis[maxn],perm[maxn];//標記陣列,全排列

void dfs(int step)//全排列,step 為當前選擇元素的數量
{
    if(step == n+1)//已經選滿 n 個數,得到全排列,深搜結束
    {
        for(int i = 1; i <= n; i++)
        {
            cout<<perm[i]<<" ";
        }
        cout<<endl;
    }
    else
    {
        //從1~n個選中一個未被選中的元素,然後繼續深搜。深搜結束之後回溯
        for(int i = 1; i <= n; i++)
        {
            if(!vis[i])//未被標記
            {
                vis[i] =1;//標記
                perm[step] = i;//記錄
                dfs(step+1);//深搜下一步
                vis[i] = 0;//回溯
            }
        }
    }
}

int main()
{
//    runfile;
    ios::sync_with_stdio(false);
    while(cin>>n)
    {
        memset(vis, 0, sizeof(vis));
        dfs(1);
    }

//    stopfile;
    return 0;
}

2、字元的全排列

#include<bits/stdc++.h>
using namespace std;

#define runfile freopen("E:/Code/CB/Root/data.txt", "r", stdin)
#define stopfile fclose(stdin)

const int maxn = 100;
int n,vis[200];//標記陣列,全排列
char s[maxn],perm[maxn];

void dfs(int step)//全排列,step 為當前選擇元素的數量
{
    if(step == n+1)//已經選滿 n 個數,得到全排列,深搜結束
    {
        for(int i = 1; i <= n; i++)
        {
            cout<<perm[i]<<" ";
        }
        cout<<endl;
    }
    else
    {
        //從1~n個選中一個未被選中的元素,然後繼續深搜。深搜結束之後回溯
        for(int i = 0; i < n; i++)
        {
            int temp = (int)s[i];//注意此處與數字標記的不同
            if(!vis[temp])//未被標記
            {
                vis[temp] =1;//標記
                perm[step] = s[i];//記錄
                dfs(step+1);//深搜下一步
                vis[temp] = 0;//回溯
            }
        }
    }
}

int main()
{
//    runfile;
    ios::sync_with_stdio(false);
    while(scanf("%d",&n) !=  EOF)
    {
        getchar();
        for(int i = 0; i < n; i++)
        {
            scanf("%c",&s[i]);
        }
        getchar();
        memset(vis, 0, sizeof(vis));
        dfs(1);
    }

//    stopfile;
    return 0;
}

3、含重複元素的全排列(首先要強制排序,然後再回溯的過程中記錄上一個值的位置,保證相同的元素不會進行互換)

#include<bits/stdc++.h>
using namespace std;

#define runfile freopen("E:/Code/CB/Root/data.txt", "r", stdin)
#define stopfile fclose(stdin)

const int maxn = 100;
int n,vis[maxn],pre;//標記陣列,全排列
char s[maxn],perm[maxn];

void dfs(int step)//全排列,step 為當前選擇元素的數量
{
    if(step == n+1)//已經選滿 n 個數,得到全排列,深搜結束
    {
        for(int i = 1; i <= n; i++)
        {
            cout<<perm[i]<<"*";
        }
        cout<<endl;
    }
    else
    {
        //從1~n個選中一個未被選中的元素,然後繼續深搜。深搜結束之後回溯
        int pre = -1;//記錄前一個選中的根節點
        for(int i = 0; i < n; i++)
        {
            if(i == 0 || s[i] != s[pre])
            {
                if(!vis[i])//未被標記
                {
                    vis[i] =1;//標記
                    perm[step] = s[i];//記錄--相當於兩個數交換的過程
                    dfs(step+1);//深搜下一步
                    vis[i] = 0;//回溯
                    pre = i;//記錄 pre
                }
            }
        }
    }
}

int main()
{
//    runfile;
    ios::sync_with_stdio(false);
    while(scanf("%d",&n) !=  EOF)
    {
        getchar();
        for(int i = 0; i < n; i++)
        {
            scanf("%c",&s[i]);
        }
        getchar();
        sort(s, s+n);//先強制排序
        memset(vis, 0, sizeof(vis));
        dfs(1);
    }

//    stopfile;
    return 0;
}