【POJ 1351】Number of Locks

Number of Locks
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 1198   Accepted: 589

Description

In certain factory a kind of spring locks is manufactured. There are n slots (1 < n < 17, n is a natural number.) for each lock. The height of each slot may be any one of the 4 values in{1,2,3,4}( neglect unit ). Among the slots of a lock there are at least one pair of neighboring slots with their difference of height equal to 3 and also there are at least 3 different height values of the slots for a lock. If a batch of locks is manufactured by taking all over the 4 values for slot height and meet the two limitations above, find the number of the locks produced.

Input

There is one given data n (number of slots) on every line. At the end of all the input data is -1, which means the end of input.

Output

According to the input data, count the number of locks. Each output occupies one line. Its fore part is a repetition of the input data and then followed by a colon and a space. The last part of it is the number of the locks counted.

Sample Input

2
3
-1

Sample Output

2: 0
3: 8

Source

 
这是一道统计方案数的题目,就是和组合数学有关的题目,但一直没想到用组合数学怎么做,于是就弃了,用DP。
DP也比较复杂。
明显要用一维来记阶段,表示i个槽的方案数。
但是,仔细想想,前面i-1不符合要求的方案数加了i下去之后是有可能变成合法的方案的!所以,我们不光要记录合法方案数,也需要记录不合法方案数。
再用一维来记录已经出现数字,其实就是一个集合,我们用二进制压缩,例如,四个数都出现过的集合就是1111(2)。
延续一般DP的手段,我们还需要记录 i 这位放的数字,再加一维。
好了,已经三维了,还不能进行DP么?是的,现在还不能,因为题目还有一个条件至少有一对相邻的高度差是3,也就是一定要出现1,4或者4,1这两对数。
我们再加一维来记录吧。。。用0,1表示即可,0表示没有出现过这种情况,1相反。
终于可以DP了。。。
g[n][S][i][0\1];
方程也是比较复杂的。
  我们枚举n-1的出现数字的集合,为什么不枚举n的状态呢??答案是可以的,但是这样写会让情况变得复杂。
  加入n-1的集合是S,第n位放的数字是i,第n-1位放的数字是j,由于我们枚举的是n-1的集合,所以,我们要判断集合中有没有j。
    (1)|i-j|=3.
      这种情况是毋庸置疑的,我们并不需要更新g[n][S + i][i][0]的状态。
        g[n][S + i][i][1] += g[n - 1][S][j][0] + g[n - 1][S][j][1];
    (2)除(1)外的情况。
      g[n][S + i][i][0] += g[n - 1][S][j][0]
      g[n][S + i][i][1] += g[n - 1][S][j][1]
答案就是S集合最少有三个元素的情况相加了。
最后需要注意的是,g数组要用long long存储。
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

long long g[20][1 << 4][4][2], f[20];

void init()
{
    memset(g, 0, sizeof(g));
    memset(f, 0, sizeof(f));
    for (int i = 0; i < 4; ++i)
        g[1][1 << i][i][0] = 1;
    for (int n = 2; n <= 17; ++n)
    {
        for (int i = 1; i < (1 << 4); ++i)
        {
            for (int j = 0; j < 4; ++j)
                for (int k = 0; k < 4; ++k)
                    if (i & (1 << k))
                    {
                        if ((j == 0 && k == 3) || (j == 3 && k == 0))
                            g[n][i | (1 << j)][j][1] += g[n - 1][i][k][0] + g[n - 1][i][k][1];
                        else
                        {
                            g[n][i | (1 << j)][j][0] += g[n - 1][i][k][0];
                            g[n][i | (1 << j)][j][1] += g[n - 1][i][k][1];
                        }
                    }
        }
        for (int i = 0; i < 4; ++i)
        {
            f[n] += g[n][15][i][1];
            for (int j = 0; j < 4; ++j)
                f[n] += g[n][15 ^ (1 << i)][j][1];
        }
    }
}

int main()
{
    init();
    int n;
    while (scanf("%d", &n) == 1 && n != -1)
        cout << n << ": " << f[n] << endl;
    return 0;
}

 

posted @ 2015-10-23 20:24  albertxwz  阅读(205)  评论(0编辑  收藏  举报