首页 > 代码库 > 百度之星2017 HDU 6114 Chess 组合数学

百度之星2017 HDU 6114 Chess 组合数学

Chess

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6114

Description

車是中国象棋中的一种棋子,它能攻击同一行或同一列中没有其他棋子阻隔的棋子。一天,小度在棋盘上摆起了许多車……他想知道,在一共N×M个点的矩形棋盘中摆最多个数的車使其互不攻击的方案数。他经过思考,得出了答案。但他仍不满足,想增加一个条件:对于任何一个車A,如果有其他一个車B在它的上方(車B行号小于車A),那么車A必须在車B的右边(車A列号大于車B)。
现在要问问你,满足要求的方案数是多少。

Input

第一行一个正整数T,表示数据组数。
对于每组数据:一行,两个正整数N和M(N<=1000,M<=1000)。

Output

对于每组数据输出一行,代表方案数模1000000007(1e9+7)。

Sample Input

1
1 1

Sample Output

1


 

题意

题目不难读=-=

题解

可以考虑使用动态规划:记dp[i][j]为第i行j列往右(包括第j列)合法的方案数,然后从后往前递推:dp[i][j]=dp[i][j+1]+dp[i+1][j+1]即可

再看看这个式子是不是似曾相识=-=下面进行一下讨论

首先,我们只考虑N<=M的情形(因为N>M的情形可以通过转置得到),那么最大放置数就是N个

事实上,由于每一列只能放一个,所以我们可以用每一行中棋子所放置的列来记录当前位置,因此得到一个排列{aN},并且满足:a1<a2<...<aN-1<aN,并且可知{aN}的个数即为所求

从M个数中抽取出N个数,有C(M,N)中选择方法,抽取出来后,按照升序排列,故排列是可以与上述的一个{aN}一一对应的,为此,总共所需的方案数是C(M,N)

【一开始考虑的dp=-=后来发现自己真真真真是个智障】

代码

 1 //HDU-6114 copyright:scidylanpno
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 const int MAXN = 1000+10;
 7 const ll MOD = 1e9+7;
 8     ll dp[MAXN][MAXN];
 9 ll ans(int N,int M)
10 {
11     memset(dp,0,sizeof dp);
12     dp[N][M]=1;
13     for(int j=M-1;j>0;j--)    dp[N][j]=dp[N][j+1]+1;
14     for(int i=N-1,j;i>0;i--)
15     {
16 
17         for(j=M-1;j>0;j--)
18         {
19             dp[i][j]=(dp[i][j+1]+dp[i+1][j+1])%MOD;
20         }
21     }
22     return dp[1][1];
23 }
24 
25 void Run()
26 {
27     int m,n;
28     scanf("%d%d",&m,&n);
29     printf("%lld",ans(min(m,n),max(m,n)));
30 }
31 
32 int main()
33 {
34     int T;
35     scanf("%d",&T);
36     while(T--)
37     {
38         Run();
39         printf("\n");
40     }
41     return 0;
42 }

 

题解链接:http://www.cnblogs.com/scidylanpno/p/7355314.html

版权所有:scidylanpno

百度之星2017 HDU 6114 Chess 组合数学