1. 程式人生 > >wustoj 1269: 劃分數 (搜尋、dp兩種解法)

wustoj 1269: 劃分數 (搜尋、dp兩種解法)

思路1:

搜尋,n分成m份,可以看成在中間切m-1次,往下搜,最後一次時統計結果就夠了。

ps:這種方法如果n、m 的範圍大一點是要TLE的,所以還是要用dp解決。

程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<cmath>
#include<set>
#include<stack>
#include<algorithm>
#define maxn 1005
#define MAXN 1000005
#define eps 1e-6
#define INF 0x3f3f3f3f
using namespace std;

int n,m,ans;

void dfs(int le,int cut,int pre)  // 當前的左邊位置 還要切幾次 上一次的長度
{
    int i,j;
    if(cut==1) // 還需要切一次的時候統計
    {
        ans+=max(0,(n-le+1)/2-pre+1);
        return ;
    }
    for(i=pre;le-1+(cut+1)*i<=n;i++) // 切一次等於改變左邊的位置
    {
        dfs(le+i,cut-1,i);
    }
}
int main()
{
    int i,j,t;
    while(~scanf("%d%d",&n,&m))
    {
        ans=0;
        dfs(1,m-1,1);
        printf("%d\n",ans);
    }
    return 0;
}


思路2:

dpdp[i][j]表示 i 分成 j 份時的方法總數。

自己dp太弱了,方程有點難想的。

方程:

dp[i][j]=dp[i-1][j-1]+dp[i-j][j];

意義:dp[i][j] 的第一份有兩種情況,

1.第一份為1,那麼將這份去掉份數少了1(j少了1),i 同時也少了1,所以這種情況由dp[i-1][j-1]推得。

2.第一份大於1,那麼後面的每份都大於1 ,將每份都減去1,則i變為 i-j ,j 不變,所以這種情況由 dp[i-j][j]推得。

程式碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define maxn 15
#define eps 1e-10
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;

int n,m,ans;
int dp[205][10];

int main()
{
    int i,j;
    memset(dp,0,sizeof(dp));
    for(i=1;i<=200;i++)
    {
        dp[i][1]=1;
    }
    for(i=1;i<=200;i++)
    {
        for(j=2;j<=i&&j<=6;j++)
        {
            dp[i][j]=dp[i-1][j-1]+dp[i-j][j];
        }
    }
    while(~scanf("%d%d",&n,&m))
    {
        printf("%d\n",dp[n][m]);
    }
    return 0;
}