题目描述:给出m个H和n个D,求由这m个H和n个D组成的字符串满足“从左到右扫描该串,字符H的累计数总是不小于字符D的累计数”的方案数


解题思路:DP
              显然,这里面可以把状态划分为dp[i][j],表示i个H和n个D含有多少成功的方案数。
              那么它的转移方程就是: dp[i][j]=dp[i-1][j]+dp[i][j-1];
              1)所有的串一定是以H或者D结尾
              3)i>j,则dp[i][j]=0;
              3)在成功的dp[i-1][j]后面中加上H,则这个是必然成立的。
              4)关键是在成功的dp[i][j-1]后面中加上D。
                   如果此时恰好是i=j-1的话,加上D就错了~~,但问题是当i=j-1的时候i<j的根本不满足2),所以这个无须考虑的。
                   那么这里只有可能是i>j-1,所以加上了D,最坏的情况就是i=j,不会出现不满足题意的情况。
              5)有人会认为可以通过一个不成功的串可以通过向其中加上一个H使其满足题设:
                   Eg:HDD+H=HDHD
                   这里给的反例是HDH+D=HDHD
                   其实很简单,HDD和HDH所出现的概率是相等的,所以一个不成功的串其中插入H势必会找到一个相对应的成功的串后面加上D
                  
                *写的时候也是凭感觉写出来,一做发现对了。后来才仔细的想了一下,其实转移也算是比较别扭的,不过总的来说这不是一道很难的DP题。


代码:
 1#include <iostream>
 2#include <cstdio>
 3#include <cstring>
 4#include <cmath>
 5
 6using namespace std;
 7
 8int m,n;
 9long long dp[50][50];
10
11int main()
12{   for(int i=1; i<=20; i++)
13        dp[i][1= i;
14    for(int i=2; i<=20; i++)
15        for(int j=2; j<=20; j++)
16            if(i >= j)
17                dp[i][j] = dp[i][j-1+ dp[i-1][j];
18            else
19                dp[i][j] = 0;
20    while(cin >> m >> n)
21        cout << dp[m][n] << endl;
22
23    return 0;
24}

25