Sicily 1902. Counting Problem

这题碉堡了。

给一个N*N的棋盘,让你放皇后。

要求:

1、每行有且只有2个Queen;

2、每列有且只有2个Queen;

规定:

如果两个棋盘,经过行交换和列交换,可以互相转换,那这两个局面等价。


目标:

给N,求出可以有多少种摆法(局面)。


分析:

这个题目,乍一看真的很无从下手。但是看到提示那个“规定”,这个等价提示了什么呢?

在“行交换”和“列交换”的过程里,  什么 是不变的?

既然行和列的排列是自由的,那他们之间联系起来的纽带是什么呢?

你会发现(其实是神明发现的。。。),是那些在同一条线上的Queen们。

两个行,比如 x 和 y ,他们如果有在同一线上的Queen,那么我们就把这2个行,分在同一组,这里简称 x和y “相关” 。 

那么假设有 a 个行 通过 “相关” 分在了同一组,我们就可以说,这是一个 有 a 个元素的组。

那么一共有多少行呢? n 行。

是不是明白了?

题目转化为——求把n分解成 不小于2 的整数 ,的分配方案数。

跟上一题《Housing》是一样的!完全背包。(详见上一篇)


dp[i][j] 表示 --- 把 i 分解成 不小于 j 的整数和 , 有多少种方案。

代码:


#include <cstdio>
using namespace std ;
#define maxn 509
#define max(a,b) a>b?a:b 

int t,n;
int dp[maxn][maxn] ;

void DP_run () {
    dp[2][2] = 1 ;
    for ( int i = 0 ; i <= 500 ; ++i ) {
        dp[i][i] = dp[i][i-1] = 1 ;   // i itself
        for ( int j = 0 ; j <= 500 ; ++j ) {
            if ( i == 0 ) dp[i][j] = 1 ;
            else if ( i < j ) dp[i][j] = 0 ;
            else {
                dp[i][j] = 0 ;
                for ( int k = max(2,j) ; k <= i ; ++k ) {
                    dp[i][j] = (dp[i][j]+dp[i-k][k])%1000007 ;
                }
            }
        }
    }
}
int main () {

    scanf ( "%d" , &t ) ;
    DP_run() ;
    while ( t-- ) {
        scanf ( "%d" , &n ) ;
        printf ( "%d\n" , dp[n][2] ) ;
    }
    //system ( "pause" ) ;
    return 0 ;
}


你可能感兴趣的:(Sicily 1902. Counting Problem)