暴力求解法 簡單列舉

2021-06-19 09:12:49 字數 3095 閱讀 9323

在剛剛開始準備學習些演算法之前,網路上很多演算法高階攻略都會建議先從一些簡單的基本演算法著手入門,其中包括「列舉,貪心,遞迴和分治,遞推,構造,模擬」這些,正好這段時間我在看的劉汝佳的《演算法競賽入門經典》這本書中涉及了很多關於基礎的東西,對於演算法的學習和acm的訓練都很有幫助,所以我打算從「藍書」入手,學習一些基本的演算法與解題技巧(前輩們的建議也大致如此),之後再開始《演算法導論》的學習。

在部落格裡貼一些學習的筆記和**,一方面是為了鞏固自己的學習,加深理解和記憶,另一方面也能更好地督促自己不偷懶!還有,在剛開始學習的時候會經常上網查詢一些解題報告,發下很多博主貼了許多連編譯都不能通過的**,真是害人害己,所以貼一些自己寫過的正確的**,也意在不浪費後來人的時間,大家共同學習,共同進步。

首先就是暴力演算法中的「列舉」。

在列舉複雜物件之前,可以先嘗試從列舉一些相對簡單的東西入手,例如整數,子串等等,儘管暴力列舉不用太動腦筋,但實現對問題進行一些簡單的分析會讓問題得到更好的解決。

7.1.1除法

輸入正整數n,按從小到大的順序輸出所有形如abcde/fghij = n的表示式,其中a~j恰好為數字0~9的乙個排列,2<=n<=79.

樣例輸入:

62樣例輸出:

79546/01283 = 62

94736/01528 = 62

/*7.1.1除法*/

#include int is_different(int x, int y);

int main()

} }

getchar();

return 0;

}int is_different(int x, int y)

while(y>0)

for(i = 0; i < count1; ++i)

for(j = i+1; j < count1; ++j)

if(bit1[i] == bit1[j])

return 0;

for(i = 0; i < count2; ++i)

for(j = i+1; j < count2; ++j)

if(bit2[i] == bit2[j])

return 0;

for(i = 0; i < count1; ++i)

for(j = 0; j < count2; ++j)

if(bit1[i] == bit2[j])

return 0;

if(count1==4)

for(i = 0; i < count2; ++i)

if(bit2[i]==0)

return 0;

if(count2==4)

for(i = 0; i < count1; ++i)

if(bit1[i]==0)

return 0;

return 1;

}

這道題看上去只是需要暴力列舉一下就可以了,但是10!的列舉量可不是開玩笑的,所以根據題意,我們只需要列舉出fghij就可以算出abcde,列舉量就降低到不到1萬,所以即使是用暴力列舉這種沒腦子的方法,也是需要分析問題的。

7.1.2最大乘積

輸入n個元素組成的序列5,你需要找出乙個乘積最大的連續子串行。如果這個最大乘積不是正數,應輸出-1(表示無解)。1≤n≤18,-10≤si≤10.

樣例輸入:

32 4 -3

52 5 -1 2 -1

樣例輸出:820

#include int main()

} printf("%d\n", max);

} getchar();

return 0;

}

最先看到題目的時候沒有想出系統的方法來把所有的子串行一一進行處理,後來看書下的分析才明白,既然是有序序列,只要枚舉子序列的起點和終點即可,這也體現出系統列舉的意義。從這道題目開始,列舉的思路與簡便(暴力)也開始漸漸有所體現。

另外子串行元素一共不超過18個,每個元素的大小也限定在絕對值為10以內,所以最大的乘積也不會超過10^18,所以乘積結果得用 long long 型別儲存。

7.1.3 分數拆分

輸入正整數k,找到所有的正整數x≥y,使得1/k = 1/x + 1/y。

樣例輸入:212

樣例輸出:

21/2 = 1/6 + 1/3

1/2 = 1/4 + 1/4

81/12 = 1/156 + 1/13

1/12 = 1/84 + 1/14

1/12 = 1/60 + 1/15

1/12 = 1/48 + 1/16

1/12 = 1/36 + 1/18

1/12 = 1/30 + 1/20

1/12 = 1/28 + 1/21

1/12 = 1/24 + 1/24

#include int main()

} getchar();

return 0;

}

咦?這和列舉有什麼關係?哦,在判斷列舉範圍的時候,因為x≥y,所以1/y ≥ 1/x。所以1/k - 1/x ≤ 1/y,即y ≤ 2k,所以得到了y的列舉範圍,只要通過y算出x即可,不必再列舉x的值,就像<7.1.1除法》那題一樣。

7.1.4 雙基回文數

如果乙個正整數n至少在兩個不同的進製b1和b2下都是回文數

(2≤b1,b2≤10),則稱n是雙基回文數(注意回文數不能包含前導0)。

輸入正整數s < 10^6,輸出比s大的最小雙基回文數。

樣例輸入:1600000

樣例輸出:1632995

#include #include #include int is_huiwen(int obj)

int main()

} }getchar();

return 0;

}

=_=那麼這題就沒什麼思路好說的了,直接從s+1開始暴力列舉,再判斷是不是雙基回文數就行。

書上關於簡單列舉的內容差不多就是這樣,更深入的學習,可以從poj1753和poj2965入手。

暴力求解法 之 簡單列舉

1 除法 輸入正整數n,按從小到大的順序輸出所有形如abcde fghij n的表示式,其中a j恰好為0 9的乙個排列,2 n 79.樣例輸入 62 樣例輸出 79546 01283 62 94736 01528 62 分析 列舉0 9的所有排列?沒這個必要。只需要列舉fghij就可以算出abcd...

暴力求解法之簡單列舉

列舉是暴力求解法最基本最簡單的一種方法,許多問題通過列舉就能找到解。當然,暴力求解法也不是無腦求解問題,通過對問題的分析減少列舉的規模可以使得演算法更加的簡潔和高效。例1.輸入正整數n,按從小到大的順序輸出所有形如abcde fghij n的表示式,其中a j恰好為數字0 9的乙個排列 可以有前導0...

暴力求解法

1 簡單列舉 輸入正整數n,按從小到大的順序輸出所有形如abcde fghij n的表示式,其中a j恰好位數字0 9的乙個排序 可以有前導0 2 n 79.樣例輸入 樣例輸出 79546 01283 62 94736 01528 62 思路 只要列舉fghij就可以算出abcde,然後判斷所有數字...