蒜頭君的新遊戲 dp

工作空閒之餘,蒜頭君經常帶着同事們做遊戲,最近蒜頭君發明了一個好玩的新遊戲:nn 位同事圍成一個圈,同事 A 手裏拿着一個兔妮妮的娃娃。蒜頭君喊遊戲開始,每位手裏拿着娃娃的同事可以選擇將娃娃傳給左邊或者右邊的同學,當蒜頭君喊遊戲結束時,停止傳娃娃。此時手裏拿着娃娃的同事即是敗者。

玩了幾輪之後,蒜頭君想到一個問題:有多少種不同的方法,使得從同事 A 開始傳娃娃,傳了 mm次之後又回到了同事 A 手裏。兩種方法,如果接娃娃的同事不同,或者接娃娃的順序不同均視爲不同的方法。例如 1->2->3->11>2>3>1 和 1->3->2->11>3>2>1 是兩種不同的方法。

輸入格式

輸入一行,輸入兩個整數 n,m(3 \leq n \leq 30,1 \leq m \leq 30)n,m(3n30,1m30),表示一共有 nn 位同事一起遊戲,一共傳 mm 次娃娃。

輸出格式

輸出一行,輸出一個整數,表示一共有多少種不同的傳娃娃方法。

樣例輸入

3 3

樣例輸出

2

/*
這道題算是道老題, 想想第一次做的時候, 好不容易想出來的,
當時也感覺真正的dp入門了.
現在做卻還是有一點波折.
首先是拆分過程, 定義子狀態:
    從 A 開始傳, 第 m 次傳到 A , 那麼只能從 A 的左邊和右邊傳過去.
    現在定義狀態 dp[m, 0] 爲傳了 m 次傳到 A 的方法數,
    狀態轉移方程爲 dp[m, 0] = dp[m - 1, 1] + dp[m - 1, (0 - 1) % n]
    dp[m - 1, 1] 表示 傳了 m - 1 次, 傳到 1 的方法數
    dp[m - 1, (0 - 1) % n] 表示 傳了 m - 1 次, 傳到 (0 - 1) % n的方法數
    
    取餘的目的是將這些人圍成一個環
*/
/*
這次做, 讓我知道通過狀態轉移方程的做法與記憶化搜索的時間有很大差異
以下兩個代碼爲第一次過的兩個代碼
*/
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 35;
int n, m;
ll dp[maxn][maxn];
ll search(int n_steps, int person);
int main()
{
    // memset(dp, -1, sizeof(dp));
    dp[0][0] = 1;
    cin >> n >> m;
    for(int i = 1; i <= m; ++i){
        for(int j = 0; j < n; ++j){
            dp[i][j] = dp[i - 1][(j + 1) % n] + dp[i - 1][(j + n - 1) % n];
        }
    }
    cout << dp[m][0] << endl;
    return 0;
}
ll search(int n_steps, int person)// TLE
{// 可能是無用的狀態有點多
    if(dp[n_steps][person] != -1)
        return dp[n_steps][person];
    if(n_steps == 0){
        if(person == 0)
            return dp[0][0] = 1;
        else
            return dp[0][person] = 0;
    }
    return search(n_steps - 1, (person + 1) % n)
            + search(n_steps - 1, (person + n - 1) % n);
}

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 35;
int dp[MAXN][MAXN];
int N, M;
int rec(int m, int pos)
{
    if(dp[m][pos] != -1)
        return dp[m][pos];
    int res;
    if(m == 0 && pos == 1)
        res = 1;
    else if(m == 0)
        res = 0;
    else if(pos == 1)
        res = rec(m - 1, 2) + rec(m - 1, N);
    else if(pos == N)
        res = rec(m - 1, 1) + rec(m - 1, N - 1);
    else
        res = rec(m - 1, pos - 1) + rec(m - 1, pos + 1);
    
    return dp[m][pos] = res;
}
int main()
{
    memset(dp, -1, sizeof(dp));
    cin >> N >> M;
    int ans = rec(M, 1);
    cout << ans << endl;
    return 0;
}

#include<iostream>
#include<cstring>
using namespace std;
int main()
{
    int n, m, dp[35][35];
    memset(dp, 0, sizeof(dp));
    cin >> n >> m;
    dp [1][0] = dp[0][1] = dp[0][n + 1] = 1;
    for(int i = 1; i <= m; ++i){
        for(int pos = 1; pos <= n; ++pos){
            dp[i][pos] = dp[i - 1][pos - 1] + dp[i - 1][pos + 1];
        }
        dp[i][n + 1] = dp[i][1];
        dp[i][0] = dp[i][n];
    }
    cout << dp[m][1] << endl;
    return 0;
}

發佈了46 篇原創文章 · 獲贊 2 · 訪問量 6918
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章