SGU 132.Another Chocolate Maniac
时间限制:0.25s
空间限制:4M
题目:
Bob非常喜欢巧克力,吃再多也觉得不够。当他的父母告诉他将要买很多矩形巧克力片为他庆祝生日时,他的喜悦是能被理解的。巧克力都是 2x1 或 1x2 的矩形。Bob的父母还为他准备了一个生日蛋糕,蛋糕可以看做 M 行 N 列的矩阵。蛋糕上的有些地方是要放蜡烛的,其他的地方都是空的。 Bob的父母要他在蛋糕上放尽可能多的巧克力片,使得任意两片不重合。然而,Bob想要把巧克力留着吃。所以他想放尽量少的巧克力这样他就可以留着更多的自己吃。为了不让父母怀疑,Bob必须装着摆放成不能再摆巧克力片了,(也就是说蛋糕上不再有两个相邻的空格)。你需要找出最少需要摆多少巧克力使得蛋糕上不存在相邻的空格和重叠的巧克力。
输入
第一行 2 个整数: M (1<=M<=70) 和 N (1<=N<=7)。接下来, M 行每行包含 N 个字符,描述蛋糕的情况。 蛋糕的i 行 j 列可能是 '*' (ASCII 42)代表插蜡烛, 或者 '.' (ASCII 46)代表是空的。
输出
最少需要摆多少巧克力块。
Solution:
被这道题折磨了一把。。。
依旧是状态压缩DP,DSF可行状态。
需要记录的是F[i][p1][p2],p1,p2分别是第i行的状态和和第i-1行的状态
F[i][p1][p2]=min(F[i][p1][p2],F[i-1][p0][p1]+当前放置的)
DFS(0,p1,p2,0),时填充的的是第i-1行。
从第1行搜起,最后要多搜一行,一直搜到m+1行。
答案不会超过int。
但是不用滚动数组的话将超内存。。。%>_<%
#include <iostream> #include <cstring> #include <cstdio> #define INF 16843009 using namespace std; int g[71], Tmi[] = {1, 2, 4, 8, 16, 32, 64, 128}; int f[2][1 << 8][1 << 8]; int n, m, x, stI, stJ,ans=INF; //状态压缩,0代表不放,1代表放 //对每一行DFS时填它的上一行 void dfs (int k, int opt1, int opt2, int cnt) { //填完k列后,如果前两行中出现了连续0,退出 if (k > 0 && (stI & Tmi[k - 1]) == 0 && (opt1 & Tmi[k - 1]) == 0) return; if (k > 1 && (opt1 & Tmi[k - 1]) == 0 && (opt1 & Tmi[k - 2]) == 0) return; if (k == m) { if (f[x ^ 1][stI][stJ] != INF) f[x][opt1][opt2] = min (f[x][opt1][opt2], f[x ^ 1][stI][stJ] + cnt); return; } //这一列不填 dfs (k + 1, opt1, opt2, cnt); //填上一行,和当前一行的同一列 if ( (opt1 & Tmi[k]) == 0 && (opt2 & Tmi[k]) == 0) dfs (k + 1, opt1 | Tmi[k], opt2 | Tmi[k], cnt + 1); //填上一行的连续两列 if (k < (m - 1) && (opt1 & Tmi[k]) == 0 && (opt1 & Tmi[k + 1]) == 0) dfs (k + 1, opt1 | Tmi[k + 1] | Tmi[k], opt2, cnt + 1); } int main() { scanf ("%d %d", &n, &m); char st[71]; for (int i = 1; i <= n; i++) { scanf ("%s", st + 1); for (int j = 1; j <= m; j++) g[i] = g[i] << 1 | (st[j] == '*'); } memset (f, 1, sizeof f); f[1][Tmi[m] - 1][g[1]] = 0; for (int k = 1; k <= n; k++) { for (int i = 0; i < Tmi[m]; i++) for (int j = 0; j < Tmi[m]; j++) { if (f[x ^ 1][i][j] != INF){ stI = i, stJ = j; dfs (0, j, g[k + 1], 0); } } memset (f[x ^ 1], 1, sizeof f[x ^ 1]); x ^= 1; } x ^= 1; for (int i = 0; i < Tmi[m]; i++) for (int j = 0; j < Tmi[m]; j++) if (f[x][i][j] > 0) ans = min (ans, f[x][i][j]); printf ("%d", ans); }