POJ 3088

Push Botton Lock

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 1613   Accepted: 1017

Description

The Frobozz Magic Lock Company is in the business of manufacturing push button style combination door locks. A push button door lock consists of a number of push buttons B, (1 ≤ B ≤ 11), labeled “1” through “B”. The lock is opened by pressing the correct sequence of button combinations and then turning the doorknob. If the sequence of presses is correct, the door magically opens.

A combination consists of 1 or more buttons being pressed simultaneously. A sequence consists of a series of combinations. A sequence must have at least one combination. Once a button has been used in a combination, it may not be used again in the same sequence. In addition, it is not necessary to use all the buttons in a sequence. For example, for B = 8:

(1-2-3)(4)(7-8)

is a valid sequence with 3 combinations (1-2-3), (4), and (7-8). Note that buttons 5 and 6 are not used in this sequence.

(1-2-3)(2-4)(5-6)

is not a valid sequence, since button 2 appears in 2 combinations (1-2-3) and (2-4).

The CEO of Frobozz, J. Pierpont Flathead, wants you to write a program that determines the number of valid sequences possible for given values of B. The program must be able to process a list of lock orders (datasets) from customers and generate a report showing the order number, the value of B, and the number of valid sequences possible. This list will always contain at least one dataset, but no more than 100 datasets.

Reference Materials:


J. Pierpont Flathead

Input

The first line of input contains a single integer N, (1 ≤ N ≤ 100), representing the number of datasets that follow. Each dataset consists of a single line of data containing a single integer B, which is the number of buttons for the lock.

Output

For each dataset, display the dataset number, a blank, the value B, a blank, and the number of valid sequences.

Sample Input

3
3
4
3

Sample Output

1 3 25
2 4 149
3 3 25

Source

Greater New York 2006

大致题意:

描述

Frobozz Magic Lock公司从事制造按钮式组合门锁的业务。按钮门锁包括多个按钮B,(1≤B≤11),标记为“1”到“B”。按下正确的按钮组合序列然后转动门把手即可打开锁定。如果按下顺序正确,门会神奇地打开。

组合包括同时按下的一个或多个按钮。序列由一系列组合组成。序列必须至少有一个组合。一旦按钮组合使用,它可能不会以相同的顺序再次使用。此外,没有必要按顺序使用所有按钮。例如,对于B = 8:

(1-2-3)(4)(7-8)

是具有3种组合(1-2-3),(4)和(7-8)的有效序列。请注意,按顺序不使用按钮5和6。

(1-2-3)(2-4)(5-6)

由于按钮2以2种组合(1-2-3)和(2-4)出现,因此不是有效序列。

Frobozz的首席执行官J. Pierpont Flathead希望您编写一个程序,确定给定B值的有效序列数。该程序必须能够处理来自客户的锁定订单(数据集)列表并生成报告显示订单号,B的值以及可能的有效序列数。此列表将始终包含至少一个数据集,但不超过100个数据集。

输入

第一行输入包含一个整数N(1≤N≤100),表示后面的数据集数量。每个数据集由包含单个整数B的单行数据组成,该整数B是锁的按钮数。

产量

对于每个数据集,显示数据集编号,空白,值B,空白和有效序列的数量。

解题思路:

可以知道,大概是要将B个数字分到不同组合,且数字不能重复出现。

N个数分到K个集合,联想到第二类斯特林数。

https://www.cnblogs.com/owenyu/p/6724661.html

其中递推公式为:S(n,k)=S(n−1,k−1)+S(n−1,k)∗k        

其中几条性质为:

  1. S(0,0)=1
  2. S(n,0)=0,n>0
  3. S(n,n)=1

首先就是枚举要取出的数的个数,然后对应某个值i会有C(n,i)中取法。

组合数:

性质:c(n,m)=c(n,n-m);  c(n,0)=1;

递推公式:c(n,m)=c(n-1,m-1)+c(n-1,m)

https://blog.csdn.net/qq_32175783/article/details/51453107

然后对于选出的i个数,再枚举分成的集合数j。

那么对于每个j,正好是对于有区分的i个元素划分成j个集合,然后再乘上j个元素的全排列数

(因为集合的排列位置不同也不算同一种)正好是第二类斯特林数的定义。

所以直接先把组合数和斯特林数的表打出来,组合数打表方法就不多说了,

对于斯特林数的打表,就是s[i][j] = s[i-1][j-1] + j*s[i-1][j] ,其中i表示可区分的元素个数,j表示要划分成的集合数。

那么也就是通过把i个可区分元素放入j个盒子中,就相当于在i-1个元素分成j-1个盒子情况下,新添加的元素新成为一个集合,还有一种是之前的i-1个元素已经分成了j个集合,那么挑一个集合将新元素放进去。

这样递推就能推出整张斯特林数的表了,然后对于每次查询算一下就好了,复杂度n^2,而n只有10几
 

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#define MAX 20
 
using namespace std;
 
typedef long long LL;
LL s[MAX][MAX];
LL c[MAX][MAX];
LL a[MAX];
 
void init ( )
{
    c[0][0] = 1;
    for ( int i = 1 ; i < 15 ; i++ )
        for ( int j = 0 ; j <=i ; j++ )
            if ( j == 0 || j == i )
                c[i][j] = 1;
            else c[i][j] = c[i-1][j-1] + c[i-1][j];
    s[1][1] = 1;
    s[1][0] = 0;
    for ( int i = 2 ; i < 15 ; i++ )
        for ( int j = 0 ; j <= i ; j++ )
            if ( j == 0 )
                s[i][j] = 0;
            else if ( j == i )
                s[i][j] = 1;
            else s[i][j] = s[i-1][j-1] + j*s[i-1][j];
    a[0] = 1;
    for ( int i = 1 ; i < MAX ; i++ )
        a[i] = a[i-1]*i;
}
 
int t,n;
 
int main ( )
{
    scanf ( "%d" , &t );
    init();
    int cc = 1;
    while ( t-- )
    {
        scanf ( "%d" , &n );
        LL ans = 0;
        for ( int i = 1 ; i <= n ; i++ )
            for ( int j = 1 ; j <= i ; j++ )
                ans += c[n][i]*s[i][j]*a[j];
        printf ( "%d %d %lld\n" , cc++ , n , ans );
    }
}
发布了158 篇原创文章 · 获赞 34 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq_40421671/article/details/96848100
POJ