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\)的友情帮助 状态压缩动态规划 本博文的大体 ...
随机推荐
- 实验一 查看CPU和内存,用机器指令和汇编指令编程
(1):使用debug,将下面的程序段写入内存,逐条执行,观察每条指令执行后,CPU中相关寄存器中内存的变化. 机器码 汇编指令 b8 20 4e mov ax,4E20H 05 ...
- PAT basic 1087
1087 有多少不同的值 (20 分) 当自然数 n 依次取 1.2.3.…….N 时,算式 ⌊n/2⌋+⌊n/3⌋+⌊n/5⌋ 有多少个不同的值?(注:⌊x⌋ 为取整函数,表示不超过 x 的最大自然 ...
- input type=file输入框
<div class="row"> <!--选择图片按钮--> <div class="col-xs-12" align=&quo ...
- Spring.Net初认识——竹子整理
留个脚印,过两天总结. 看到知乎上有人对于DI|IOC 的解释,满不错,收藏下先 作者:OneNoodle链接:http://www.zhihu.com/question/23277575/answe ...
- Java的内存回收
一.java引用的种类 1.对象在内存中的状态 可达状态:当一个对象被创建后,有一个以上的引用变量指向它. 可恢复状态: 不可达状态:当对象的所有关联被切断,且系统调用所有对象的finalize方法依 ...
- sql优化系列1
sql中索引是否会用到,进而影响查询效率. 带通配符(%)的like语句 1.不能用null作索引,任何包含null值的列都将不会被包含在索引中.即使索引有多列这样的情况下,只要这些列中有一列含有nu ...
- easyui-combogrid匹配查询
用到easyui-combogrid,数据比较少的情况,可以一页就显示完毕,然后直接下拉选择.但是对于数据量比较大的情况,一页显示全部显然不合适,好在从easyui-combogrid的数据加载方式可 ...
- loj2059 「TJOI / HEOI2016」字符串
字符串好难啊不会啊 #include <iostream> #include <cstdio> using namespace std; int n, m, rnk[10000 ...
- 手把手教你启用RemoteFX以及Hyper-V GPU卸载
[TechTarget中国原创] 微软的RemoteFX特性可以帮助改善虚拟机图形密集型应用工作负载的性能. 服务器虚拟化已经成熟到大多数工作负载都能够在虚拟机内运行的程度.毫无疑问,与其他工作负载相 ...
- flask url_for()和redirect的区别
一. 两者用来重定向的时候,被操作的对象不同. redirect直接是url,就是app.route的路径参数. url_for()是对函数进行操作. from flask import Flask, ...