洛谷P1706及algorithm庫的第一步探索

EaKal7發表於2020-12-03

先放題目,不多BB

題目描述
輸出自然數 1 到 n 所有不重複的排列,即 n 的全排列,要求所產生的任一數字序列中不允許出現重複的數字。
輸入格式
一個整數 n。
輸出格式
由 1~n 組成的所有不重複的數字序列,每行一個序列。

每個數字保留 5 個場寬。
輸入輸出樣例
輸入#1:
3
輸出#1:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

Hint
1<=n<=9

憨憨程式碼:

//Create by EaKal7

#include <stdio.h> //這種方法在n=9||8是直接超過了2E
#include <algorithm>
#include <string.h>
#include <time.h>
#include <bits/stdc++.h>
using namespace std;
int a[50] = {0};
int n, num, p;
int r;
int flag[10];
int start;
int end_n;
int pailie(int n)
{
  for (int i = 1; i <= n; i++)
  {
    if (flag[i] == 0)
    {
      return 0;
    }
  }
  return 1;
}
void Pritn(int e)
{
  int temp[10];
  int k = 0;
  while (e)
  {
    temp[k++] = e % 10;
    e /= 10;
  }
  for (int i = k - 1; i >= 0; i--)
  {
    printf("%5d", temp[i]);
  }
  printf("\n");
}
int main()
{

  scanf("%d", &n);
  r = n - 1;
  start = 1;
  end_n = 9;
  while (r--)
  {
    start = start * 10 + 1;
    end_n = end_n * 10 + 9;
  }
  for (int i = start; i < end_n; i++)
  {
    for (int j = 1; j <= n; j++)
    {
      flag[j] = 0;
    }
    r = i;
    flag[r % 10] = 1;
    while (r /= 10)
    {
      flag[r % 10] = 1;
    }
    if (pailie(n) == 1)
    {
      Pritn(i);
    }
  }
  return 0;
}

執行正常但是運算量太大,直接爆了,而且思想過於複雜,考慮到dfs想到應該可以dfs

DFS版本:

#include<bits/stdc++.h>
using namespace std;
int n,pd[100],used[100];
void printt()
{
    int i;
    for(i=1;i<=n;i++)
    printf("%5d",used[i]);
    cout<<endl;
}
void dfs(int k)//深搜函式,當前是第k格
{
    int i;
    if(k==n) //填滿
    {
        printt();
        return;
    }
    for(i=1;i<=n;i++)
    {
        if(!pd[i])
        {
            pd[i]=1;//標記一下
            used[k+1]=i;//把這個數填入陣列
            dfs(k+1);//填下一個
            pd[i]=0;//回溯
        }
    }
}
int main()
{
    cin>>n;
    dfs(0);//注意,這裡是從第**0**格開始的!
    return 0;
}

這裡就考慮dfs會不會大題小作,或者過於麻煩,所以蒟蒻查閱blog,發現了一個有序全排序的神器,algorithm庫裡的next_permutation,可產生1~n的全排列有如下程式碼:

#include <stdio.h>
#include <algorithm>
using namespace std;
int main(){
    int n;
    while(scanf("%d",&n)&&n){
        int a[1000];
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        sort(a,a+n);//可以自行測試一下刪除後的結果
        do{
            for(int i=0;i<n;i++)
                printf("%d ",a[i]);
            printf("\n");
        }while(next_permutation(a,a+n));
    }
    return 0;
}

next_permutation這個函式直接對1~n的全排列,並且是從陣列中當前的字典序開始依次增大直至到最大字典序。注:這個函式是直接改變陣列地址裡的數值的。
所以直接貼上改動後的程式碼:

next_permutation版本:

//Create by EaKal7
//next_permutation的debug nice!!!!
#include <stdio.h>
#include <algorithm>
using namespace std;
int main()
{
  int n, p, temp[9];
  while (scanf("%d", &n) != EOF)
  {
    for (int i = 0; i < n; i++)
    {
      temp[i] = i + 1;
      printf("%5d", temp[i]);
    }
    printf("\n");
    while (next_permutation(temp, temp + n))
    {
      for (int i = 0; i < n; i++)
      {
        printf("%5d", temp[i]);
      }
      printf("\n");
    }
  }
  return 0;
}

總結:這個函式直接將全排序有序輸出,將一些程式碼濃縮,有一點sort和排序的味道了。

PS:algorithm這個庫裡還有好多挺好用的函式建議一一探討
PPS:第一篇部落格 by EaKal7 2020.12.3
參考部落格:
關於全排列 next_permutation() 函式的用法