题目链接 Clear The Matrix

题意 给定一个$4 * n$的矩形,里面的元素为$'.'$或$'*'$。现在有$4$种正方形可以覆盖掉$'*'$,正方形的边长分别为$1,2,3,4$。

求把整个矩形变成全$'.'$的最小代价。

考虑状压DP

设$f[i][j]$为前$i$列已经全部变成'.',第$i + 1$到第$i + 4$列的这$16$个格子状态为$j$的最小花费。

这$16$个格子标号如下

$0$   $4$   $8$   $12$

$1$   $5$   $9$   $13$

$2$   $6$  $10$  $14$

$3$   $7$  $11$  $15$

我们可以枚举$0,1,2,3$这$4$个格子。以当前格子为左上角的正方形的边长。

其中$0$号格子可以放边长为$0, 1, 2, 3, 4$的正方形;

$1$号格子可以放边长为$0, 1, 2, 3$的正方形;

$2$号格子可以放边长为$0, 1, 2$的正方形;

$3$号格子可以放边长为$0, 1$的正方形;

放边长为$0$的正方形等效为不放。

当枚举的这些正方形可以完全盖住$0,1,2,3$这$4$个格子的时候,就可以进行状态转移。

状态稍微有点复杂,用二进制位表示……

时间复杂度$O(n * 2^{16} * 5!)$

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i) const int N = 1e3 + 10;
const int S = 1 << 16; char s[N];
int f[N][S + 2];
int a[6][N];
int c[10];
int g[10];
int n;
int pre[N];
int ans;
int cnt, mask; void up(int &a, int b){ if (a > b) a = b;}
inline get(int x){ return x ^ (S - 1);} int main(){ scanf("%d", &n);
rep(i, 1, 4) scanf("%d", c + i); rep(i, 1, 4){
scanf("%s", s + 1);
rep(j, 1, n) a[i][j] = s[j] == '*';
} rep(k, 0, n){
rep(i, 0, S + 1) f[k][i] = 1e9;
} cnt = -1;
mask = 0;
rep(i, 1, 4){
rep(j, 1, 4){
++cnt;
if (a[j][i]) mask |= (1 << cnt);
}
}
f[0][mask] = 0; g[0] = 0;
g[1] = 1;
g[2] = (1 << 0) ^ (1 << 1) ^ (1 << 4) ^ (1 << 5);
g[3] = (1 << 0) ^ (1 << 1) ^ (1 << 2);
g[3] ^= ((1 << 4) ^ (1 << 5) ^ (1 << 6));
g[3] ^= ((1 << 8) ^ (1 << 9) ^ (1 << 10));
g[4] = (1 << 16) - 1; rep(k, 0, n){
int extra = 0;
rep(j, 1, 4) if (a[j][k + 5]) extra |= (1 << (j + 11)); rep(j, 0, S - 1){
if (f[k][j] >= 1e9) continue;
rep(aa, 0, 4){
rep(bb, 0, 3){
rep(cc, 0, 2){
rep(dd, 0, 1){
int cnt = get(g[aa]) & get(g[bb] << 1) & get(g[cc] << 2) & get(g[dd] << 3);
if ((cnt & j & 15) == 0){
int nowmask = cnt & j;
nowmask >>= 4;
nowmask ^= extra;
up(f[k + 1][nowmask], f[k][j] + c[aa] + c[bb] + c[cc] + c[dd]);
}
}
}
}
}
}
} ans = 1e9;
rep(i, n - 4, n) ans = min(ans, f[i][0]);
printf("%d\n", ans);
return 0;
}

 

我们可以考虑使用滚动数组,于是空间大大节省

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define MP make_pair
#define fi first
#define se second typedef long long LL; const int N = 1e3 + 10;
const int S = 1 << 16; char s[N];
int f[2][S + 2];
int a[6][N];
int c[10];
int g[10];
int n;
int pre;
int ans;
int cnt, mask; void up(int &a, int b){ if (a > b) a = b;}
inline get(int x){ return x ^ (S - 1);} int main(){ scanf("%d", &n);
rep(i, 1, 4) scanf("%d", c + i); rep(i, 1, 4){
scanf("%s", s + 1);
rep(j, 1, n) a[i][j] = s[j] == '*';
} rep(k, 0, 1) rep(i, 0, S + 1) f[k][i] = 1e9; cnt = -1;
mask = 0;
rep(i, 1, 4){
rep(j, 1, 4){
++cnt;
if (a[j][i]) mask |= (1 << cnt);
}
}
f[0][mask] = 0;
pre = 0; g[0] = 0;
g[1] = 1;
g[2] = (1 << 0) ^ (1 << 1) ^ (1 << 4) ^ (1 << 5);
g[3] = (1 << 0) ^ (1 << 1) ^ (1 << 2);
g[3] ^= ((1 << 4) ^ (1 << 5) ^ (1 << 6));
g[3] ^= ((1 << 8) ^ (1 << 9) ^ (1 << 10));
g[4] = (1 << 16) - 1; rep(i, 0, n){
int extra = 0;
rep(j, 1, 4) if (a[j][i + 5]) extra |= (1 << (j + 11)); rep(j, 0, S + 1) f[pre ^ 1][j] = 1e9; rep(j, 0, S - 1){
if (f[pre][j] >= 1e9) continue;
rep(aa, 0, 4){
rep(bb, 0, 3){
rep(cc, 0, 2){
rep(dd, 0, 1){
int cnt = get(g[aa]) & get(g[bb] << 1) & get(g[cc] << 2) & get(g[dd] << 3);
if ((cnt & j & 15) == 0){
int nowmask = cnt & j;
nowmask >>= 4;
nowmask ^= extra;
up(f[pre ^ 1][nowmask], f[pre][j] + c[aa] + c[bb] + c[cc] + c[dd]);
}
}
}
}
}
}
pre ^= 1;
} printf("%d\n", f[pre][0]);
return 0;
}

不过这个做法还不是最优的= =

官方题解给出的做法是只存后面12个格子的状态的

因为当考虑某一列的时候一旦用到$4*4$的正方形,其他边长的正方形就不用再考虑了……直接无视掉。

这样的话可以直接从$f[k][nowmask]$转移到$f[k + 1][0]$

时间复杂度$O(n * 2^{12} * 96)$

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i) const int N = 1e3 + 10;
const int S = 1 << 12; char s[N];
int f[2][S + 2], a[6][N], c[10], g[10];
int n, x, cnt, mask, ans; void up(int &a, int b){ if (a > b) a = b;}
inline get(int x){ return x ^ (S - 1);} int main(){ scanf("%d", &n);
rep(i, 1, 4) scanf("%d", c + i); rep(i, 1, 4){
scanf("%s", s + 1);
rep(j, 1, n) a[i][j] = s[j] == '*';
} rep(k, 0, 1) rep(i, 0, S + 1) f[k][i] = 1e9; cnt = -1;
mask = 0; rep(i, 1, 3){ rep(j, 1, 4){ ++cnt; if (a[j][i]) mask |= (1 << cnt); }} f[0][mask] = 0;
x = 0; g[0] = 0;
g[1] = 1;
g[2] = 51;
g[3] = 1911; rep(i, 0, n){
int extra = 0;
rep(j, 1, 4) if (a[j][i + 4]) extra |= (1 << (j + 7));
rep(j, 0, S + 1) f[x ^ 1][j] = 1e9; rep(j, 0, S - 1){
if (f[x][j] >= 1e9) continue;
rep(aa, 0, 3){
rep(bb, 0, 3){
rep(cc, 0, 2){
rep(dd, 0, 1){
int cnt = get(g[aa]) & get(g[bb] << 1) & get(g[cc] << 2) & get(g[dd] << 3);
if ((cnt & j & 15) == 0){
mask = (cnt & j) >> 4;
mask ^= extra;
up(f[x ^ 1][mask], f[x][j] + c[aa] + c[bb] + c[cc] + c[dd]);
}
}
}
}
}
up(f[x ^ 1][0], f[x][j] + c[4]);
}
x ^= 1;
} printf("%d\n", f[x][0]);
return 0;
}

Codeforces 903F Clear The Matrix(状态压缩DP)的更多相关文章

  1. Codeforces 903F Clear the Matrix

    题目大意 考虑一个 $4$ 行 $n$ ($4\le n\le 1000$)列的矩阵 $f$,$f$ 中的元素为 * 或 . . 对 $f$ 进行若干次如下变换: 将一个 $k\times k$($1 ...

  2. Codeforces 580D Kefa and Dishes(状态压缩DP)

    题目链接:http://codeforces.com/problemset/problem/580/D 题目大意:有n盘菜每个菜都有一个满意度,k个规则,每个规则由x y c组成,表示如果再y之前吃x ...

  3. Codeforces C. A Simple Task(状态压缩dp)

    题目描述:  A Simple Task time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  4. Codeforces 4538 (状态压缩dp)Little Pony and Harmony Chest

    Little Pony and Harmony Chest 经典状态压缩dp #include <cstdio> #include <cstring> #include < ...

  5. 状态压缩dp(hdu2167,poj2411)

    hdu2167 http://acm.hdu.edu.cn/showproblem.php?pid=2167 给定一个N*N的板子,里面有N*N个数字,选中一些数字,使得和最大 要求任意两个选中的数字 ...

  6. Light OJ 1316 A Wedding Party 最短路+状态压缩DP

    题目来源:Light OJ 1316 1316 - A Wedding Party 题意:和HDU 4284 差点儿相同 有一些商店 从起点到终点在走过尽量多商店的情况下求最短路 思路:首先预处理每两 ...

  7. Light OJ 1406 Assassin`s Creed 状态压缩DP+强连通缩点+最小路径覆盖

    题目来源:Light OJ 1406 Assassin`s Creed 题意:有向图 派出最少的人经过全部的城市 而且每一个人不能走别人走过的地方 思路:最少的的人能够走全然图 明显是最小路径覆盖问题 ...

  8. HDU 6125 Free from square 状态压缩DP + 分组背包

    Free from square Problem Description There is a set including all positive integers that are not mor ...

  9. 状态压缩dp初学__$Corn Fields$

    明天计划上是要刷状压,但是作为现在还不会状压的\(ruoruo\)来说是一件非常苦逼的事情,所以提前学了一下状压\(dp\). 鸣谢\(hmq\ juju\)的友情帮助 状态压缩动态规划 本博文的大体 ...

随机推荐

  1. BFS:HDU3085-Nightmare Ⅱ(双向BFS)

    Nightmare Ⅱ Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 32768/32768 K (Java/Others) Tot ...

  2. Linux基本命令运行

    文件基本操作: 增删查改: 创建文件:touch(创建文件和修改文件或者目录的时间戳),vim.vi(编辑/创建文件),mkdir(创建文件目录) 移动和修改文件名:mv 删除文件:rm –rf(强制 ...

  3. Vs2012 打开项目 自动关闭 并停止工作 解决方法

    来源:http://q.cnblogs.com/q/52530/ http://www.microsoft.com/zh-cn/download/details.aspx?id=36020 下载并安装 ...

  4. sc.exe

    sc.exe 编辑 本词条缺少名片图,补充相关内容使词条更完整,还能快速升级,赶紧来编辑吧! 服务管理程序:可用sc.exe远程创建 外文名 sc.exe 停止事件服务 sc  stop eventl ...

  5. Azure继续降价云 价格战就此终结?

    [TechTarget中国原创] 刚刚跨入2016年,就听到了云降价这样一个消息,但是我们却不要期望降价之风如去年一样呼呼不绝. 微软公司在本周宣称,他们将在下个月对其D系列虚拟机实施高达17%的降价 ...

  6. IOS开发---菜鸟学习之路--(二十三)-直接利用键值对的方式来处理数据的感想

    首先声明,本文纯粹只是做为本人个人新手的理解.文中的想法我知道肯定有很多地方是错的. 但是这就是我作为一个新人的使用方法,对于大牛非常欢迎指导,对于喷子请绕道而行. 由于这是早上跟我学长讨论数据处理时 ...

  7. linux VIM编辑器常用指令

    一般模式 查看文本-移动光标 [Ctrl] + [f] 屏幕『向前』移动一页 [Ctrl] + [b]  屏幕『向后』移动一页  n<space> 按下数字后再按空格键,光标会向右移动这一 ...

  8. http状态码相关知识(复制)

    HTTP报文是面向文本的,报文中的每一个字段都是一些ASCII码串,各个字段的长度是不确定的.HTTP有两类报文:请求报文和响应报文. HTTP请求报文 一个HTTP请求报文由请求行(request ...

  9. SRCNN(一)

    SRCNN学习(一):demo_SR.m 一.demo_SR.m 使用方法 1.Place the "SRCNN" folder into "($Caffe_Dir)/e ...

  10. BZOJ 1877:[SDOI2009]晨跑(最小费用最大流)

    晨跑DescriptionElaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑.仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑. 现在给出一张学校附近的地图,这张地图中包含N个 ...