題目鏈接:點擊查看
題目大意:給出一棵無窮大的有根樹,每個節點都有 k 個兒子,每條邊都有權值,分別是 1 ~ k,現在問從根節點向下走,有多少條路徑的權值和等於 n ,且至少存在一條邊權大於等於 d 的邊
題目分析:讀完題感覺像揹包問題,花了一個小時想了個三維 dp,四層 for 用來轉移,正確性肯定是沒問題的,只不過有點太畫蛇添足了:
dp[ i ][ j ][ k ]:到了第 i 層,容量爲 j ,最大值爲 k 時的方案數,轉移的話一層枚舉層數,一層枚舉下一個數字,一層枚舉容量,一層枚舉最大值,非常囉嗦
訓練完看了看別人寫的題解,發現自己真的好菜啊好菜啊好菜啊好菜啊好菜啊
dp[ i ][ 0/1 ] 代表容量爲 i 時,是否含有大於等於 d 的邊權的方案數,轉移的話一層循環枚舉當前的容量,一層循環枚舉最後一次的數字用來轉移即可
本來以爲 dp 已經入門,足以應付這種簡單 dp,然鵝還是太菜了啊
代碼:
n^2
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=110;
const int mod=1e9+7;
LL dp[N][N];//dp[i][j]:總和爲i,是否包含大於等於d的數的方案數
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.ans.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n,k,d;
scanf("%d%d%d",&n,&k,&d);
dp[0][0]=1;
for(int i=1;i<=n;i++)//枚舉當前的容量
for(int j=1;j<=k&&j<=i;j++)//枚舉最後一次的數字
{
if(j>=d)
dp[i][1]=(dp[i][1]+dp[i-j][0]+dp[i-j][1])%mod;
else
{
dp[i][1]=(dp[i][1]+dp[i-j][1])%mod;
dp[i][0]=(dp[i][0]+dp[i-j][0])%mod;
}
}
printf("%lld\n",dp[n][1]);
return 0;
}
n^4
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=110;
const int mod=1e9+7;
LL dp[N][N][N];//dp[i][j][k]:到了第i個數字,容量爲j,最大值爲k時的方案數
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.ans.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n,k,d;
scanf("%d%d%d",&n,&k,&d);
dp[0][0][0]=1;
for(int s=1;s<=n;s++)//枚舉回合
for(int i=1;i<=k;i++)//枚舉數字
for(int j=i;j<=n;j++)//枚舉容量
for(int t=0;t<=k;t++)//枚舉最大值
dp[s][j][max(t,i)]=(dp[s][j][max(t,i)]+dp[s-1][j-i][t])%mod;
LL ans=0;
for(int i=1;i<=n;i++)
for(int j=d;j<=k;j++)
ans=(ans+dp[i][n][j])%mod;
printf("%lld\n",ans);
return 0;
}