您的位置:首页 > 其它

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

2017-08-13 17:39 218 查看
题意:

对于任何一个車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
[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  百度 hdu dp