HDU 6114 Chess(DP)2017百度之星初赛(B) 1001

题意:

对于任何一个車A,如果有其他一个車B在它的上方(車B行号小于車A),那么車A必须在車B的右边(車A列号大于車B)。在满足该条件的情况下,摆最多棋子的 方案数有多少。

思路:

自底向上来思考,用n表示行数,m表示列数。先假设一种极端情况(n<m),先摆好前n-1行,如下图。

  n:3   m:5(1表示已经放了一个棋子,0表示不放旗子,2表示可以选择放旗子)

10000
01000
00222

设第n-1行摆放棋子为j列。


通过上图可以分析出来,这种情况下,摆放方案有m-j种。

再看另一种情况。
10000
00100
00022

显然上述的结论也是成立的,那我们怎么通过最后一行推出前面行的情况呢?
我们先做一个处理,将每个点所处的该行的右边放棋子的方案数都加到自身上,即dp[i][j]+=dp[i][j+1…n](j>=i)

注意!!下面图中的数字为以该点为 左上顶点做棋盘的边界  的 所有方案数 。而不是表示之前放旗子的状态
什么意思呢?就比如该点为(i,j)时,以n-i+1为行数,m-j+1为列数做棋盘的所有方案数。

先从最后一行开始。(前面的n-1行还未处理所以都为0)

00000
00000
00321


当j<i时,不可能有放棋子的可能,因为要求所放的棋子数最大!这点应该很好想。


处理完最后一行,我们怎么把数目转移到n-1行上呢?

其实通过之前的观察我们就知道,如果我们确定一个点要放棋子,那这种情况下,所有的方案数就等于dp[i+1][j+1]。即取决于它右下角的那个位置的方案数。

dp的状态转移公式:

dp[i][j]+=dp[i+1][j+1]+dp[i][j+1]; (i+1<=n && j+1<=m)


我们继续处理完吧✧(≖ ◡ ≖✿),不理解的话,再看看下面的图,或许会比较好理解。

00000
06310
00321


104100
06310
00321


✨✨最后dp[1][1]就是我们要求的答案啦~


附上代码~

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M=1e9+7;
typedef long long ll;
int n,m;
ll dp[1005][1005];
int main(){
    int t;
    int nt,mt;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&nt,&mt);
        n=min(nt,mt);//为了方便处理,都让行数<=列数
        m=max(nt,mt);
        memset(dp,0, sizeof(dp));
        for (int j = m; j >=n ; --j) {
            dp[n][j]=1;
        }
        for (int i = n; i >=1; --i) {
            for (int j = m; j >=i ; --j) {
                if(j+1<=m && i+1<=n)  dp[i][j]=(dp[i][j]+dp[i+1][j+1])%M;
                if(j+1<=m)  dp[i][j]=(dp[i][j]+dp[i][j+1])%M;
            }
        }
        printf("%I64d\n",dp[1][1]);

    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值