標籤:結構 排列 ace 否則 元素 資料結構 n+1 clear ==
【問題描寫敘述】
給定一個正整數N代表火車數量。0<N<10,接下來輸入火車入站的序列,一共N輛火車,每輛火車以數字1-9編號。
要求以字典序排序輸出火車出站的序號。
輸入:
有多組測試用例,每一組第一行輸入一個正整數N(0<N<10),第二行包含N個正整數,範圍為1到9。
輸出:
輸出以字典序排序的火車出站序號,每一個編號以空格隔開,每一個輸出序列換行。詳細見sample。
例子輸入:
3
1 2 3
例子輸出:
1 2 3
1 3 2
2 1 3
2 3 1
3 2 1
【解題思路一】
棧具有先進後出、後進先出的特點,因此,不論什麼一個調度結果應該是1 ,2 ,3 ,4全排列中的一個元素。因為進棧的順序是由小到大的,所以出棧序列應該滿足下麵條件:對於序列中的不論什麼一個數其後面全部比它小的數應該是倒序的,比如4321 是一個有效出棧序列,1423不是一個有效出棧結果(4 後面比它小的兩個數 2 ,3 不是倒序)。
據此。本題能夠通過演算法產生n 個數的全排列,然後將滿足出棧規則的序列輸出。
依此遞迴定義。遞迴演算法例如以下:
#include<stdio.h> int cont=1; void print(int str[],int n); void perm(int str[],int k,int n) { int i,temp; if(k==n-1)print(str,n);//k和n-1相等。即一趟遞迴走完 else{ for(i=k;i<n;i++){//把當前節點元素與興許節點元素交換 temp=str[k]; str[k]=str[i]; str[i]=temp;//交換 perm(str,k+1,n);//把下一個節點元素與興許節點元素交換 temp=str[i]; str[i]=str[k]; str[k]=temp;//恢複原狀 } } } /* 本函數推斷整數序列 str[] 是否滿足進出棧規則, 若滿足則輸出*/ void print(int str[],int n) { int i,j,k,l,m,flag=1,b[2]; for(i=0;i<n;i++) /* 對每一個str[i] 推斷其後比它小的數是否為降序序列*/ { m=0; for(j=i+1;j<n&&flag;j++){ if (str[i]>str[j]) { if (m==0) b[m++]=str[j];//記錄str[i]後比它小的數 else { //假設之後出現的數比記錄的數還大,改變標記變數 if (str[j]>b[0]) flag=0; //否則記錄這個更小的數 else b[0]=str[j]; } } } } if(flag) /* 滿足出棧規則則輸出 str[] 中的序列*/ { printf(" %2d:",cont++); //輸出序號 for(i=0;i<n;i++) printf("%d",str[i]);//輸出序列 printf("\n"); } } int main() { int str[100],n,i; printf("input a int:"); /* 輸出排列的元素個數*/ scanf("%d",&n); for(i=0;i<n;i++) /* 初始化排列集合*/ str[i]=i+1; //第i個節點賦值為i+1 printf("input the result:\n"); perm(str,0,n); //調用遞迴 printf("\n"); return 0; }
【解題思路二】
此處所謂字典序排序的意思是這n輛火車有多少種出站的可能順序(也就是資料結構中的棧有多少種出棧順序)。思路為用三個變數分別儲存待進站火車,站中火車和已出站火車,當中待進站火車用Queue(隊列)儲存和站中火車採用stack(棧)儲存,已出站火車採用StringBuilder來儲存,詳細實現是採用遞迴的方法,遞迴函式的參數為當前待進站火車、站中火車、已出站火車的值所組成的三元組,遞迴結束條件是。未進站火車和站中火車均為空白。此時輸出已出站火車即為全部出站的一種可能,遞推關係為對於當前情況有讓下一輛火車進站或讓站中的一輛火車出站兩種可能,對於兩種可能分別調用遞迴函式。就可以得出問題的解。
【Java 實現】
【解題思路三】
該問題能夠提煉成為給出進棧序列。求出全部的出棧順序。該題是一道類比題,類比進棧出棧的順序。對於每個元素進棧後 都能夠有2種行為:出棧或者駐留在棧中。整個過程能夠用一個樹的形式來表達。因此採用回朔法(回溯法的過程就是一課樹的形式)
//回溯法。其核心就是迴圈+遞迴。為了表示正確性,當中每一步操作(如改動資料,進棧等) //都應該有對應的對稱操作還原(如將改動資料還原,出棧等) #include<stdio.h> #include<string.h> #include<vector> #include<algorithm> using namespace std; int num; int input[10]; int output[10]; int output_index; int heap[10]; int heap_index; vector<int* >vec; void DF(int n); void df(int n) { if(heap_index==0) return ; //退出棧 放入輸入隊列中 output[output_index++]=heap[--heap_index]; //對稱1 heap[heap_index]=0; for(int i=0;i<2;i++) { if(i==0) df(n); else DF(n+1); } heap[heap_index++]=output[--output_index]; //對稱1 output[output_index]=0; } void DF(int n) { heap[heap_index++]=input[n]; //放入 。對稱2 if(n==num-1) //該函數退出時(一般在回溯法中,在函數出口內部是不存在對稱結構,可是該題中存在其它函數df調用該回溯函數,故返回到) { int temp=heap_index; output[output_index++]=heap[--heap_index]; //對稱3 heap[heap_index]=0; while(heap_index) output[output_index++]=heap[--heap_index]; int *p=(int *)malloc(sizeof(int)*num); for(int i=0;i<output_index;i++) p[i]=output[i]; vec.push_back(p); while(temp) //對稱3 { heap[heap_index++]=output[--output_index]; output[output_index]=0; temp--; } heap[--heap_index]=0; //對稱2 return ; } for(int i=0;i<2;i++) { if(i==0) df(n); else DF(n+1); //i==1的時候就是不將資料退出棧 } heap[--heap_index]=0; //對稱2 } bool cmp(int* t1,int* t2) { for(int i=0;i<num;i++) { if(t1[i]==t2[i]) continue; return t1[i]<t2[i]; } return true; } int main() { freopen("a.txt","r",stdin); while(scanf("%d",&num)!=EOF) { memset(input,0,sizeof(input)); memset(output,0,sizeof(input)); memset(heap,0,sizeof(input)); output_index=0; heap_index=0; vec.clear(); for(int i=0;i<num;i++) scanf("%d",input+i); DF(0); sort(vec.begin(),vec.end(),cmp); for(unsigned int i=0;i<vec.size();i++) { for(int j=0;j<num-1;j++) printf("%d ",vec[i][j]); printf("%d\n",vec[i][num-1]); } } return 0; }
【解題思路四】
STL方法:1、若n=1那麼就一種相片順序。2、n>1時先求出n-1的出棧順序。再分開將n插入n-1之前。n-1之後和每個n-1之後的每個數!
#include <iostream>#include <string>#include <algorithm>#include <vector>using namespace std;void helper(string &inTrain,vector<string> &outTrain,int index){ if(index == inTrain.size()){ return; }//if if(index == 0){ string outNum(""); outNum += inTrain[index]; outTrain.push_back(outNum); }//if else{ vector<string> newOutTrain; // 出棧序列 int size = outTrain.size(); // 第index輛火車進棧 for(int i = 0;i < size;++i){ // 第i個出棧序列 int count = outTrain[i].size(); // 尋找前一個進棧的火車下標 int targetIndex; for(int j = 0;j < count;++j){ if(inTrain[index-1] == outTrain[i][j]){ targetIndex = j; break; }//if }//for string tmp(outTrain[i]); for(int j = targetIndex;j <= count;++j){ tmp.insert(tmp.begin()+j,inTrain[index]); newOutTrain.push_back(tmp); tmp.erase(tmp.begin()+j); }//for }//for swap(outTrain,newOutTrain); }//else helper(inTrain,outTrain,index+1);}vector<string> TrainLeft(string inTrain){ vector<string> result; int size = inTrain.size(); if(size <= 0){ result; }//if helper(inTrain,result,0); sort(result.begin(),result.end()); return result;}int main(){ int n; //freopen("C:\\Users\\Administrator\\Desktop\\c++.txt","r",stdin); while(cin>>n){ string train(""); int num; for(int i = 1;i <= n;++i){ cin>>num; train += num + ‘0‘; }//for vector<string> trainNum = TrainLeft(train); // 輸出 int size = trainNum.size(); for(int i = 0;i < size;++i){ int count = trainNum[i].size(); for(int j = 0;j < count;++j){ if(j == 0){ cout<<trainNum[i][j]; }//if else{ cout<<" "<<trainNum[i][j]; }//else }//for cout<<endl; }//for }//while return 0;}
C++ HOJ 火車進站