Day 05 DP_Basic 02 总结
今日AC题目列表:
HOJ 1192 Dollars
HOJ 1714 Minimax Triangulation
HOJ 2156 Colored stones
HOJ 2558 maxsum
HOJ 2662 Pieces Assignment
今天效率超级低啊,> . <,下午竟然手残把数组下标写反了。
HOJ 2622 Pieces Assignment 解题报告
题目大意:
有一个n*m的棋盘(n、m≤80,n*m≤80)要在棋盘上放k(k≤20)个棋子,使得任意两个棋子不相邻(每个棋子最多和周围4个棋子相邻)。求合法的方案总数。
具体思路:
注意到n*m<=80,可得到max(min(n,m)) 为8,于是最大可以用1<<8-1表示一行的棋子的状态。
于是f[i][j][r] = Σf[i-1][k][r-t(j)] t(j)是j这种状态里面棋子的个数,如果k & j != 0表示上一行和这一行有矛盾,此种状态不成立。
初始值f[0][0][0] = 1
每次判断j这种状态自身是否合法即可。
附上代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
long long f[81][1<<9][21];
inline int getnum(int x)
{
int s = 0 , tmp = 0;
while (x)
{
if (s && (x & 1)) return -1;
if (s = (x & 1)) tmp++;
x = x >> 1;
}
return tmp;
}
int main()
{
int n, m, t;
while(scanf("%d%d%d", &n, &m, &t) != EOF)
{
if (n < m) swap(n, m);
memset(f,0,sizeof(f));
f[0][0][0] = 1;
for (int i = 1; i <= n; i++)
for (int r = 0; r <= t; r++)
for (int j = 0; j < (1<<m); j++)
{
int num = getnum(j);
if (num == -1 || num > r) continue;
for (int k = 0; k < (1<<m); k++)
{
if (getnum(k) == -1 || (k & j) ) continue;
f[i][j][r] += f[i-1][k][r-num];
}
}
long long ans = 0;
for (int i = 0; i < (1<<m); i++) ans += f[n][i][t];
printf("%lld\n",ans);
}
return 0;
}

浙公网安备 33010602011771号