Rooks---LightOj1005(排列组合)
题目链接:http://lightoj.com/volume_showproblem.php?problem=1005
题意就是在一个n*n的方格中放k个棋子,每一行每一列都不能有两个棋子,问有多少种方法,和8皇后问题很像, 但是8皇后问题可以用暴力搜索,但是本题n的取值范围较大,不能用搜索;在比赛的时候我找到了公式,但是由于乘除的顺序问题导致错误;就是A(n,k)*A(n,k)/ A(k,k);即C(n, k)*A(n, k);
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> using namespace std; #define N 4000100 int main() { int T, t=1; int n, m; long long ans; scanf("%d", &T); while(T--) { scanf("%d %d", &n, &m); ans = 1; for(int i=n; i>n-m; i--) ans*=i; for(int i=1; i<=m; i++) ans/=i; for(int i=n; i>n-m; i--) ans*=i; printf("Case %d: %lld\n", t++, ans); } return 0; }
还有一种方法是dp:
#include<stdio.h> #include<string.h> int main() { int T, n, m, t=1; long long dp[31][910]; memset(dp, 0, sizeof(dp)); for(int i=0; i<=30; i++) dp[i][0] = 1; for(int i=1; i<31; i++) { for(int j=1; j<=i*i; j++) { dp[i][j] = dp[i-1][j] + dp[i-1][j-1]*(2*i-2*j+1) + dp[i-1][j-2]*((i-j+1)*(i-j+1)); } } scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); printf("Case %d: %lld\n", t++, dp[n][m]); } return 0; }