全排列(來自藍橋杯)
阿新 • • 發佈:2018-12-24
做了道藍橋杯的題,發現並不會做,不過這個題做了也算漲了個知識點。
題目:
相信大家都知道什麼是全排列,但是今天的全排列比你想象中的難一點。我們要找的是全排列中,排列結果互不相同的個數。比如:aab
的全排列就只有三種,那就是aab
,baa
,aba
。
程式碼框中的程式碼是一種實現,請分析並填寫缺失的程式碼
下面是題目的程式碼
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int N=1e3; char str[N], buf[N];//buffer int vis[N], total, len; void arrange(int num) { if (num == len){ printf("%s\n", buf); total++; return; } for (int i = 0; i < len; ++i) { if (!vis[i]) { int j; for (j = i + 1; j < len; ++j) { if (/*在這裡填寫必要的程式碼*/) { break; } } if (j == len) { vis[i] = 1; buf[num] = str[i]; arrange(num + 1); vis[i] = 0; } } } } int main() { while (~scanf("%s",str)) { len = strlen(str); sort(str, str + len); total = 0; buf[len] = '\0'; arrange(0); printf("Total %d\n", total); } return 0; }
那麼下面是完整的程式碼:
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int N=1e3; char str[N], buf[N];//buffer int vis[N], total, len; void arrange(int num) { if (num == len) { printf("%s\n", buf); total++; return; } for (int i = 0; i < len; ++i) { if (!vis[i]) { int j; for (j = i + 1; j < len; ++j) { if ( str[i] == str[j] && vis[j]/*在這裡填寫必要的程式碼*/) { break; } } if (j == len) { vis[i] = 1; buf[num] = str[i]; arrange(num + 1); vis[i] = 0; } } } } int main() { while (~scanf("%s",str)) { len = strlen(str); sort(str, str + len); total = 0; buf[len] = '\0'; arrange(0); printf("Total %d\n", total); } return 0; }
填空的地方的意思是,如果i的後面有和s[i] 相等且訪問過的字元,則不可以(break),一旦break,j 就不能等於len,就不能繼續遞迴。那麼怎麼理解這個呢?
先想一下簡化的問題吧,假如輸入的字串不重複,例如abcd,那麼就是簡單的dfs了,一個for迴圈加一個vis判斷,如果判斷可以,繼續遞迴。
當有重複的字元時候就比較麻煩了,比如aab,單純的用遞迴會輸出重複的。那麼怎麼加上限定條件呢。
這裡,我們讓重複的這些字元只順序輸出一遍,這樣就不會重複
這是什麼意思呢,比如說aabc,我們只允許第一個a訪問後再訪問第二個a,不允許訪問第二個,再第一個。
再如,abacda,那三個a只能按順序訪問。
原理是什麼呢,用了點高中學的排列組合的知識,先排重複的,例如我們搞abacda這個例子, 先排三個a, 就是 aaa,那麼剩下的就相當於直接插入到aaa中,那麼如果我們aaa如果按多種順序排,就會產生多種結果,所以只能按順序訪問。
那麼又如何用演算法實現呢,直接加個if判斷就行了,判斷i之後的有沒有訪問過的且相等的。例如,aabc這個例子,我們第一輪選完之後,到了第二個a,然後進入遞迴,for迴圈又從0開始,到了第一個a,然後從這個之後去判斷有沒有訪問過的a,結果判斷有,違反了順序,所以結束。
這個題目的關鍵也就是排除重複的