标签:
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;
}
【POJ 1351】Number of Locks
标签:
原文地址:http://www.cnblogs.com/albert7xie/p/4905581.html