NOIP2004 火星人(全排列)

2021-07-24 16:55:17 字數 2377 閱讀 6522

題目描述:火星人共有n個手指,每個手指分別代表著1-n共n個數,可以通過改變這個這n個手指的順序來改變值的大小。但是人類想要和火星人交流,就必須通過科學家,科學家先將火星人講的話(手指表示的數)翻譯成我們能理解的語言(如火星人共3個手指,則123 132 213 231 312 321分別代表1 2 3 4 5 6),然後告訴你乙個數,你把這個數和火星人講的話加起來回給科學家,科學家再翻譯成火星人的語言。本題給出火星人的手指數n、要加的數m和手指的順序num[n],要求輸出火星人收到的回話。

剛開始看到這個題目,還是有點懵逼的,但是知道它是乙個全排列問題,所以趕緊的去了解了一下全排列,順利地解決了這個問題。

本題就是要求求出num[n]經過m次排列後的結果。

對於一系列的數,比如int num[5] = 這個陣列,要想對它進行全排列,要經過以下幾個步驟:

1.判斷該陣列能不能進行全排列

對於乙個陣列來說,如果他為num[5] = ,那麼也就沒有必要再去全排列了,因為他已經是最大的數字了,沒有後繼。所以,想要判斷一系列數能不能進行全排列,判斷他有沒有後繼(即這個數是否存在非遞減的兩個數),如果有(存在),那就可以進行排列。

判斷是否能進行全排列的**:

bool hasnext()

2.如何進行全排列(當時想這個想了挺久的==)

在確定這一系列的數有後繼之後,那如何去找到它的後繼呢?要明確,乙個數的後繼要滿足兩個條件:比這個數大、在比這個數大的數裡面最小。

首先,我們從右往左遍歷這個陣列,找出乙個數num[i],滿足num[i]>num[i-1],然後用top將這個i記錄下來(即top為極大值點),並且確定了乙個要交換的數num[top-1];

接著,我們要確定第二個要交換的數, 而第二個要交換的數為num[top]-num[n]中最小的數並且這個數要大於第乙個被交換的數num[top-1];

然後,交換兩個數;

最後,如果交換之後,num[top]及其後面的數如果還是單調遞減的,那就將其位置對調,得到最小的。

找出極大值得top並記錄

for( int i = n-1; i >0; i--)

}

確定第二個要交換的數

int mm = top;//mm為要交換數的下標

//如果top後面還有比top前面的數(也就是num[top-1)小的話,就先交換那個小的數

for( int i = top; i < n; i++)

交換兩個數

void _swap( int *a, int *b)

_swap(&num[mm],&num[top-1]);

得到最小

for(int i=0;i<=(top+n-1)/2-top;i++)

_swap(&num[i+top],&num[n-1-i]);

大概的思路就是這個樣子了==

可能講的還不是太清楚,其實對於全排列問題,用遞迴、c++的庫函式都可以完成的。

原始碼:

#includeusing namespace std;

const int maxn = 10000+5;

int num[maxn];

int n,m;

//個人覺得這個不寫也沒問題,但是為了安全,還是寫著吧

int hasnext()

void _swap( int *a, int *b)

void next()

//找出第二個要交換的數

int mm = top;

for( int i = top; i < n; i++)

_swap( &num[top-1], &num[mm]);

for( int i = 0; i <= (top+n-1)/2-top; i++)

_swap( &num[i+top], &num[n-1-i]);

}int main()

printf("%d",num[0]);

for( int i = 1; i < n; i++)

printf(" %d",num[i]);

printf("\n");

}return 0;

}

//用vector容器不用陣列更容易實現呢==

用c++中的庫函式

#include#includeusing namespace std;

const int maxn = 10000+5;

int num[maxn];

int main()

return 0;

}

NOIP普及組 火星人 貪心,排列)

人類終於登上了火星的土地並且見到了神秘的火星人。人類和火星人都無法理解對方的語言,但是我們的科學家發明了一種用數字交流的方法。這種交流方法是這樣的,首先,火星人把乙個非常大的數字告訴人類科學家,科學家破解這個數字的含義後,再把乙個很小的數字加到這個大數上面,把結果告訴火星人,作為人類的回答。火星人用...

NOIP2004P4 火星人 題解

題目描述略 本題題意為求給定長度為 n 的數列的後第 m 個全排列 字典序 從右向左查詢最大的下標 i 0 i n 1 使得 a i a i 1 從左向右查詢最小的元素 a j i 1 j n 1 使得 a i a j 交換 a i 和 a j 逆置翻轉 a i 1 n 1 演算法分析 我們可以發現...

P1088 NOIP2004 普及組 火星人

目錄演算法求解 參考文章 題目傳送門 題目描述 人類終於登上了火星的土地並且見到了神秘的火星人。人類和火星人都無法理解對方的語言,但是我們的科學家發明了一種用數字交流的方法。這種交流方法是這樣的,首先,火星人把乙個非常大的數字告訴人類科學家,科學家破解這個數字的含義後,再把乙個很小的數字加到這個大數...