日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

*【洛谷 - P1025】数的划分(dfs 或 dp 或 母函数,第二类斯特林数Stirling)

發布時間:2023/12/10 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 *【洛谷 - P1025】数的划分(dfs 或 dp 或 母函数,第二类斯特林数Stirling) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題干:

題目描述

將整數n分成k份,且每份不能為空,任意兩個方案不相同(不考慮順序)。

例如:n=7,k=3,下面三種分法被認為是相同的。

1,1,5
1,5,1
5,1,1

問有多少種不同的分法。

輸入輸出格式

輸入格式:

?

n,kn,k?(6<n \le 2006<n≤200,2 \le k \le 62≤k≤6)

?

輸出格式:

?

11個整數,即不同的分法。

?

輸入輸出樣例

輸入樣例#1:?復制

7 3

輸出樣例#1:?復制

4

說明

四種分法為:
1,1,51,1,5;
1,2,41,2,4;
1,3,31,3,3;
2,2,32,2,3.

解題報告:

? ? 這題也是今年十月份左右的時候清理工邀請賽的第二簽到題。。當時想不到辦法了直接dfs過的。偶然翻洛谷看到了原題、、見到了dp解法和母函數的解法。

? ?dfs很簡單,做個簡單的剪枝就好了,這是個看似o(200^6)但是實際上遠遠沒有這么高復雜度的dfs。今天先補上dp的解法,母函數的以后復習的時候再說。

AC代碼1:(dfs)

#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair #define fi first #define se second using namespace std; const int MAX = 2e5 + 5; ll dp[505][505]; int n,k; void dfs(int last,int sum,int cur) {if(cur==k) {if(sum==n) cnt++;return;}for(int i=last; sum+i*(k-cur)<=n; i++) {//剪枝,只用枚舉到sum+i*(k-cur)<=n為止dfs(i,sum+i,cur+1);} } int main() {cin>>n>>k;dfs(1,0,0);cout << cnt <<endl;return 0 ;}

AC代碼2:(dp)

dp[i][j]代表把i個小球放到j個盒子中的方法數。

一個簡單的想法:以一個數為基準,逐步減少分割數 或 減少待分割數 。(這里選擇1)

分為兩種情況(因為是無序的所以認為每次都是劃分完后所有球從小到大排序了)

a.至少有一個盒子只有一個小球的情況數

b.沒有一個盒子只有一個小球的情況數

這樣進行劃分是因為這種分類可以使a和b都有能寫出來的表達式:

a.因為盒子不加區分,那么1的情況數與“將n-1個小球放到k-1個盒子中”的情況數一樣

b.沒有一個盒子只有一個小球,那么把每個盒子中拿出來一個小球,對應的是“把(n-k)個小球放到k個盒子中的情況數”

這個b情況可以理解為:第一個數不為1時,可以視為先在所有的位置上都加上一個1再對于所有的位置用新的總數求次數,

所以定了的是占有了總數j個,位置仍然是j個,與原來相比沒有變化。所以b情況的方案數=把i-j個球放到j個盒子中的方案數。

然后將上面的思路化為動態轉移方程:

#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair #define fi first #define se second using namespace std; const int MAX = 2e5 + 5; ll dp[505][505]; int main() {int n,k;for(int i = 1; i<=303; i++) /*dp[i][0] = */dp[i][1] = 1;//那一句到底有沒有必要加啊,反正是這個狀態用不到?dp[1][1] = 1;for(int i = 2; i<=303; i++) {for(int j = 2; j<=i; j++) {if(i-j >= 0) dp[i][j] = dp[i-1][j-1] + dp[i-j][j];//其實要是j<=i這么寫的話這一行前面的那個if也可以不要了//else dp[i][j] = 0;}}cin>>n>>k;cout << dp[n][k]<<endl;return 0 ;}

總結:

? ?注意一下dp這里的數組不能開dp[505][25]這樣,如果要這么寫的話那就加上else也是錯的,,因為你想啊i會遍歷到300,那j也會跟著到300,所以會越界啊就修改別的數據了,,所以保險起見要么你在內層循環寫上j<=min(k,i)或者min(15,i),要么就直接開個打數組來存這些沒用的狀態就好了嘛反正也是用不到的狀態,,恰好也不會卡住空間,,干脆就開這么大好了。

題解https://www.luogu.org/problemnew/solution/P1025

總結

以上是生活随笔為你收集整理的*【洛谷 - P1025】数的划分(dfs 或 dp 或 母函数,第二类斯特林数Stirling)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。