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; }