Codeforces 903F Clear The Matrix(状态压缩DP)
题目链接 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)的更多相关文章
- Codeforces 903F Clear the Matrix
题目大意 考虑一个 $4$ 行 $n$ ($4\le n\le 1000$)列的矩阵 $f$,$f$ 中的元素为 * 或 . . 对 $f$ 进行若干次如下变换: 将一个 $k\times k$($1 ...
- Codeforces 580D Kefa and Dishes(状态压缩DP)
题目链接:http://codeforces.com/problemset/problem/580/D 题目大意:有n盘菜每个菜都有一个满意度,k个规则,每个规则由x y c组成,表示如果再y之前吃x ...
- Codeforces C. A Simple Task(状态压缩dp)
题目描述: A Simple Task time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- Codeforces 4538 (状态压缩dp)Little Pony and Harmony Chest
Little Pony and Harmony Chest 经典状态压缩dp #include <cstdio> #include <cstring> #include < ...
- 状态压缩dp(hdu2167,poj2411)
hdu2167 http://acm.hdu.edu.cn/showproblem.php?pid=2167 给定一个N*N的板子,里面有N*N个数字,选中一些数字,使得和最大 要求任意两个选中的数字 ...
- Light OJ 1316 A Wedding Party 最短路+状态压缩DP
题目来源:Light OJ 1316 1316 - A Wedding Party 题意:和HDU 4284 差点儿相同 有一些商店 从起点到终点在走过尽量多商店的情况下求最短路 思路:首先预处理每两 ...
- Light OJ 1406 Assassin`s Creed 状态压缩DP+强连通缩点+最小路径覆盖
题目来源:Light OJ 1406 Assassin`s Creed 题意:有向图 派出最少的人经过全部的城市 而且每一个人不能走别人走过的地方 思路:最少的的人能够走全然图 明显是最小路径覆盖问题 ...
- HDU 6125 Free from square 状态压缩DP + 分组背包
Free from square Problem Description There is a set including all positive integers that are not mor ...
- 状态压缩dp初学__$Corn Fields$
明天计划上是要刷状压,但是作为现在还不会状压的\(ruoruo\)来说是一件非常苦逼的事情,所以提前学了一下状压\(dp\). 鸣谢\(hmq\ juju\)的友情帮助 状态压缩动态规划 本博文的大体 ...
随机推荐
- git 使用规范
git使用资料: https://github.com/peak-c/my-git 公司内部使用开发规范: 一. 代码库介绍 个人开发库(git@gitlab.adrd.sohuno.com:sper ...
- Python linecache模块
Table of Contents 1. linecache 1.1. 其它 2. 参考资料 linecache 今天分享一个python的小模块: linecache, 可以用它方便地获取某一文件某 ...
- RCP 项目启动图片设置
第一步 选择启动图片命名为 splash.bmp 第二步 添加 扩展点 然 后在右边的扩展元素细节中填入相应的信息,比如我们在这里的application属 性 为 org.vwpolo.rcp.ex ...
- easyui-numberbox限定仅输入数字
许多必填项都涉及到数字,比如电话号码,身份证号这些要求用户在输入时只能输入数字.Easyui提供了数字框控件,允许用户只输入数字, <td> <input id="ssd& ...
- IOS笔记048-数据存储
IOS数据存储的几种方式 XML属性列表(plist) 归档 Preference(偏好设置) NSKeyedArchiver归档(NSCodin ...
- 一个iOS程序员眼中的跨域问题
摘要: 跨域问题是web开发领域一个常见的问题,相信每个web开发者都遇到"跨域"的问题 最近公司的iOS开发任务比较少,所以自己最近开始了Web开发的任务,在用H5做了很多页面, ...
- win7分盘(复制)
1/10 右击“计算机”选择“管理” 2/10 打开管理之后点击“磁盘管理器”,在想要新建磁盘的分区上右击,点击“压缩卷” 3/10 在“输入压缩空间量”后面输入需要新建磁盘的大小,输入的单位为MB( ...
- X-UA-Compatible设置IE浏览器兼容模式
文件兼容性用来告诉IE,让它如何来编译你的网页. 指定 文件兼容性模式 以下是指定为Emulate IE7 mode 兼容性范例. <html> <head> <!-- ...
- File IO(NIO.2):读、写并创建文件
简介 本页讨论读,写,创建和打开文件的细节.有各种各样的文件I / O方法可供选择.为了帮助理解API,下图以复杂性排列文件I / O方法 在图的最左侧是实用程序方法readAllBytes,read ...
- 禁用jQuery chosen的选择下拉菜单
想法是启用被勾掉之后,左侧下拉框禁用.这是chosen()的 disabled之后需要更新一下.就这样,还有别的方法的话请分享,O(∩_∩)O哈哈~