lightoj 1005 - Rooks(组合数学)

37 篇文章 0 订阅
1005 - Rooks
Time Limit: 1 second(s)Memory Limit: 32 MB

Sample Input

Output for Sample Input

8

1 1

2 1

3 1

4 1

4 2

4 3

4 4

4 5

Case 1: 1

Case 2: 4

Case 3: 9

Case 4: 16

Case 5: 72

Case 6: 96

Case 7: 24

Case 8: 0

A rook is a piece used in the game of chess which is played on a board of square grids. A rook can only move vertically or horizontally from its current position and two rooks attack each other if one is on the path of the other. In the following figure,
the dark squares represent the reachable locations for rook R1 from its current position. The figure also shows that the rook R1 and R2 are in attacking positions where R1 and R3 are
not. R2 and R3 are also in non-attacking positions.

Now, given two numbers n and k, your job is to determine the number of ways one can put k rooks on an n x n chessboard so that no two of them are in attacking positions.

Input

Input starts with an integer T (≤ 350), denoting the number of test cases.

Each case contains two integers n (1 ≤ n ≤ 30) and k (0 ≤ k ≤ n2).

Output

For each case, print the case number and total number of ways one can put the given number of rooks on a chessboard of the given size so that no two of them are in attacking positions. You may safely assume that this number will be less than 1017


题目大意是说在国际象棋的棋盘上摆放“车”这个棋子,给你n和k,n是指n * n大小的棋盘,k是指有多少个棋子,求可以摆放的方案总数。

一开始以为是搜索,不知道能不能写出来,没写过。。。后来知道是一个很简单的组合数学

先引进几个概念:

排列:

n个不同元素中取出mm≤n)个元素的所有排列的个数,叫做从n个不同元素中取出m个元素的排列数,用符号Anm(或Pnm,或nPm)表示。

   
,选出来的数字之间还有顺序的

组合数:从m个不同元素中,任取n(n≤m)个元素并成一组,叫做从m个不同元素中取出n个元素的一个组合;从m个不同元素中取出n(n≤m)个元素的所有组合的个数,叫做从m个不同元素中取出n个元素的组合数。选出来的数字之间没有顺序的;

组合数性质
一般组合数都用杨辉三角写,递推公式就是;c[i][j] = c[i-1][j] + c[i-1][j-1];

思路:
简单点说就是:一开始要从n行中选出k行,这k行是没有顺序的,因为没有限制的,交换也没有什么关系,然后选k列的时候,就有限制了,被行数限制,所以之间有顺序了。

我们不妨设题目中的答案为M(n,k),n和k分别对应题目中的n和k。同样的,我们仍然从简单的情况分析。

当k>n时,显然不可能摆放所有的棋子,所以此时M(n,k)=0;

所以我们现在只讨论当k小于等于n时的情况。

当k=1时,我们可以在任意一个位置摆放棋子,所以此时M(n,1)=n^2;

当k=2时,首先假设k小于等于n,我们可以这样想,先在棋盘的n竖列中选取两列,随后,只要两个棋子的“高度”不同(把棋盘看作一个坐标系,选取好竖列后相当于确定了其横坐标,下面我们只需要考察纵坐标即可)就可以记作一种可行方案。那么显然,子问题转化为在高度为n的单元格上有n个棋子,其中只有两个棋子是不透明的,其余棋子为透明棋子。问有多少种排列方式。答案很明显是A(n,2)。在考虑到第一步的答案C(n,2),由分布计数的结论,M(n,2)=A(n,2) * C(n,2)。

我觉得解释到这里就不需要接着解释了,对于一般的M(n,k),我们有

<span style="color:#ff0000;">M(n,k) = A(n,k) * C(n,k) ;(k>n)
       = 0 ;(0<K<=n)</span>

代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
long long fact(int n, int k)
{
    long long c[35][35];
    long long sum  = 1;
    for(int i = n; i >= n-k+1; i--)
        sum *= i;
    for(int i = 0; i <= n; i++) //组合数的核心代码
        c[i][0] = 1;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= i; j++)
            c[i][j] = c[i-1][j] + c[i-1][j-1];
    return c[n][k] * sum;
}
int main()
{
    int t, n, k, l = 0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        if(k > n) {printf("Case %d: 0\n",++l);continue;}
        if(k <= n) printf("Case %d: %lld\n",++l,fact(n,k));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值