標籤:style blog http color io for ar 問題
一.全排列無重複字元
#include<stdio.h>#include<string.h>char buf[1024];void func(int index);void swap(int index1,int index2);int main(){ memset(buf,0,sizeof(buf)); sprintf(buf,"abc"); func(0); return 0;}void func(int index){ if(index == strlen(buf)-1) { printf("%s\n",buf); } else { for(int i=index;i<strlen(buf);i++)//注意這裡i是從index開始的,這裡做的決策是每個剩餘的字元都可能做index位 { swap(index,i); func(index+1); swap(index,i); } }}void swap(int index1,int index2){ char temp = buf[index1]; buf[index1] = buf[index2]; buf[index2] = temp;}
二.全排列有重複字元
由於全排列就是從第一個數字起每個數分別與它後面的數字交換。我們先嘗試加個這樣的判斷——如果一個數與後面的數字相同那麼這二個數就不交換了。如122,第一個數與後面交換得212、221。然後122中第二數就不用與第三個數交換了,但對212,它第二個數與第三個數是不相同的,交換之後得到221。與由122中第一個數與第三個數交換所得的221重複了。所以這個方法不行。
換種思維,對122,第一個數1與第二個數2交換得到212,然後考慮第一個數1與第三個數2交換,此時由於第三個數等於第二個數,所以第一個數不再與第三個數交換。再考慮212,它的第二個數與第三個數交換可以得到解決221。此時全排列產生完畢。
這樣我們也得到了在全排列中去掉重複的規則——去重的全排列就是從第一個數字起每個數分別與它後面非重複出現的數字交換。
#include<stdio.h>#include<string.h>char buf[1024];void func(int index);void swap(int index1,int index2);bool isSwap(int index1,int index2);int main(){ memset(buf,0,sizeof(buf)); sprintf(buf,"abb"); func(0); return 0;}void func(int index){ if(index == strlen(buf)-1) { printf("%s\n",buf); } else { for(int i=index;i<strlen(buf);i++) { if(isSwap(index,i)) { swap(index,i); func(index+1); swap(index,i); } } }}void swap(int index1,int index2){ char temp = buf[index1]; buf[index1] = buf[index2]; buf[index2] = temp;}bool isSwap(int index1,int index2)//判斷前面是否已經有與buf[index2]相同的字元{ if(index1 == index2) return true; else { for(int i=index1;i<index2;i++) { if(buf[i] == buf[index2]) { return false; } } return true; }}
三.從m個字元中取n個組合,如abc的組合有a、bc、ab、ac、bc、abc
方法一:利用位元運算來實現求組合,例如:對於字元序列“abc”,讓其與1-7的二進位相與,每次輸出對應二進位為1的那幾位,即可輸出全部組合。
#include<stdio.h>#include<string.h>char buf[1024];void func();int main(){ memset(buf,0,sizeof(buf)); sprintf(buf,"abb"); func(); return 0;}void func(){ int n = strlen(buf); if(n > 31) { return; } for(int i=1;i<(1<<n);i++) { for(int j=0;j<n;j++) { if((1<<j)&i) { printf("%c",buf[j]); } } printf("\n"); }}
方法二:先決定選幾個字元,再遍曆字串,依次做兩種決策:第i個字元在結果中;第i個字元不在結果中,最後看字元數是否與開始選定的值相等
代碼略
四.八皇后問題
題目:在8×8的國際象棋上擺放八個皇后,使其不能相互攻擊,即任意兩個皇后不得處在同一行、同一列或者同一對角斜線上。中的每個黑色格子表示一個皇后,這就是一種合格擺放方法。請求出總共有多少種擺法。
這就是有名的八皇后問題。解決這個問題通常需要用遞迴,而遞迴對編程能力的要求比較高。因此有不少面試官青睞這個題目,用來考察應聘者的分析複雜問題的能力以及編程的能力。
由於八個皇后的任意兩個不能處在同一行,那麼這肯定是每一個皇后佔據一行。於是我們可以定義一個數組ColumnIndex[8],數組中第i個數字表示位於第i行的皇后的列號。先把ColumnIndex的八個數字分別用0-7初始化,接下來我們要做的事情就是對數組ColumnIndex做全排列。由於我們是用不同的數字初始化數組中的數字,因此任意兩個皇后肯定不同列。我們只需要判斷得到的每一個排列對應的八個皇后是不是在同一對角斜線上,也就是數組的兩個下標i和j,是不是i-j==ColumnIndex[i]-Column[j]或者j-i==ColumnIndex[i]-ColumnIndex[j]。
#include<stdio.h>#include<string.h>int buf[8];void func(int index);void swap(int index1,int index2);bool isLegal();int main(){ memset(buf,0,sizeof(buf)); for(int i=0;i<8;i++) { buf[i] = i; } func(0); return 0;}void func(int index){ if(index == 7) { if(isLegal()) { for(int i=0;i<7;i++) { printf("%d,",buf[i]); } printf("%d\n",buf[7]); } } for(int i=index;i<8;i++) { swap(i,index); func(index+1); swap(i,index); }}void swap(int index1,int index2){ if(index1==index2) { return; } else { int temp = buf[index1]; buf[index1] = buf[index2]; buf[index2] = temp; }}bool isLegal(){ for(int i=0;i<7;i++) { for(int j=i+1;j<8;j++) { if((i-j) == (buf[i]-buf[j]) || (i-j) == (buf[j]-buf[i])) { return false; } } } return true;}