状态压缩DP总结
POJ1185 炮兵部队问题:
在平原上才能放置炮兵,每个炮兵的上下左右2格之内都不能出现别的炮兵
可以考虑在当前行放置炮兵它的右侧和下侧绝对不会出现炮兵即可,左侧和上侧就能省去考虑
明显的状态压缩dp题,但是题目所给的有10列,因为每行都与前两行的状态有关,那么也就是根据当前,上一行,上上行3行状态来修改
dp[i][v][u]的状态方程
因为这里直接3重循环会爆,但是我们很容易发现,可以预处理一些关于行的合法状态,那么状态数就少了很多,接下来考虑的时候就省去了行上的相关影响
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; const int N = <<;
int dp[][][] , state[N];
int can[] , tot[] , cnt;
char str[]; void init_dfs(int k , int u , int v)
{
if(k<){
tot[cnt] = v;
can[cnt++] = u;
return;
}
init_dfs(k- , u|(<<k) , v+);
init_dfs(k- , u , v);
} int main()
{
// freopen("a.in" , "r" , stdin);
int n,m;
while(scanf("%d%d" , &n , &m) != EOF)
{
for(int i= ; i<=n ; i++){
scanf("%s" , str);
state[i] = ;
for(int j= ; j<(int)strlen(str) ; j++){
state[i] <<= ;
if(str[j] == 'P') state[i]+=;
}
// cout<<"state: "<<state[i]<<endl;
}
//找到所有符合的状态,减少状态数
cnt = ;
init_dfs(m- , , );
// cout<<cnt<<endl; if(n==){
int maxn=;
for(int i= ; i<cnt ; i++)
if((state[]&can[i]) == can[i])
maxn = max(maxn , tot[i]);
printf("%d\n" , maxn);
continue;
} memset(dp , , sizeof(dp));
for(int i= ; i<cnt ; i++){
for(int j= ; j<cnt ; j++){
int t1 = state[]&can[i] , t2 = state[]&can[j];
if(t1 == can[i] && t2 == can[j] && !(can[i]&can[j]))
{
// cout<<"test: "<<i<<" "<<j<<" "<<can[i]<<" "<<can[j]<<" tot: "<<tot[i]<<" "<<tot[j]<<endl;
dp[][i][j] = tot[i] + tot[j];
}
}
}
state[] = (<<m)-;
for(int i= ; i<=n ; i++){
for(int u= ; u<cnt ; u++){
if((state[i]&can[u]) < can[u]) continue;
for(int v= ; v<cnt ; v++){
if((state[i-]&can[v]) < can[v]) continue;
if((can[v]&can[u])) continue;
for(int w= ; w<cnt ; w++){
if((state[i-]&can[w]) < can[w]) continue;
if((can[v]&can[w]) || (can[u]&can[w])) continue;
dp[i][v][u] = max(dp[i][v][u] , dp[i-][w][v] + tot[u]);
}
}
}
}
int maxn = ;
for(int i= ; i<cnt ; i++){
for(int j= ; j<cnt ; j++)
maxn = max(maxn , dp[n][i][j]);
}
printf("%d\n" , maxn);
}
return ;
}
POJ 2411 木板拼接问题:
在n*m的方格中,放1*2或者2*1的木板,问有多少摆放的种数
题目会超int,答案输出用long long
这里用dp[i][u]表示到达第 i 行时状态为 u ,且前面行的格子已经全部被木板填充完全,所能达到的方法种数
每次对于当前行的状态只跟上一行有关,dp[i+1][u] += dp[i][v]
通过v可以拼出 u 的情况,我们总是在u,v上放2*1的板,或只在u 上放1*2的板,不能在v上放1*2的板,这样会与原来 v 作为当前行时在其上放1*2的情况重复
且必须保证全部放完后,上一行v 全部填充满(v == (1<<m)-1) ,才更新数据
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define ll long long
ll dp[][]; void dfs(int i , int u , int v , int full , int k , ll val)
{
if(k<){
if(v == full) dp[i][u] += val;
return ;
}
if(k>= && !(u&(<<(k-)))) dfs(i , u|(<<(k-)) , v , full ,k- , val);
if(!(u&(<<k)) && !(v&(<<k))) dfs(i , u|(<<k) , v|(<<k) , full , k- , val);
if(!(v&(<<k))) return ;
dfs(i , u , v , full , k- , val);
} int main()
{
// freopen("a.in" , "r" , stdin);
int n,m;
while(scanf("%d%d" , &n , &m) ,n||m)
{
memset(dp , , sizeof(dp));
dfs( , , (<<m)- , (<<m)- , m- , );
for(int i= ; i<=n ; i++){
for(int j= ; j<(<<m) ; j++){
if(dp[i-][j]) dfs(i , , j , (<<m)- , m- , dp[i-][j]);
}
}
printf("%I64d\n" , dp[n][(<<m)-]);
}
return ;
}
HDU2280 填充问题:
将所给的积木装入平面上,保证最后剩余的格数能够尽可能的少
因为积木最大也就两行,所以每次当前行只受上一行的影响
dp[i][u]记录当前 i 行 状态 为 u 时剩余的格子的最小数目
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = ; int dp[N][] , state[N];
char str[]; int cnt_0(int u)
{
int ans = ;
while(u){
if(u&) ans--;
u>>=;
}
return ans;
} void dfs1(int i , int u , int cnt , int k) //k为当前的长度,从0开始
{
if(k < ){
dp[i][u] = min(dp[i][u] , cnt);
return ;
}
if(k >= && !(u&(<<(k-)))){
int v = u|(<<(k-));
dfs1(i , v , cnt- , k-);
}
dfs1(i,u,cnt,k-);
}
//u为当前行状态,v为上一行状态,cnt为当前行0的数量
void dfs2(int i , int u , int v , int cnt , int k)
{
if(k < ){
dp[i][u] = min(dp[i][u] , cnt);
return ;
}
if(k>=){
if(!(u&(<<(k-)))){
int p = u|(<<(k-));
dfs2(i , p , v , cnt- , k-);
}
if(!(u&(<<(k-))) && !(v&(<<(k-)))){
int p = u|(<<(k-));
int q = v|(<<(k-));
dfs2(i , p , q , cnt- , k-);
}
if(!(u&(<<(k-))) && !(v&(<<k))){
int p = u|(<<(k-));
int q = v|(<<k);
dfs2(i , p , q , cnt- , k-);
}
if(!(v&(<<(k-))) && !(u&(<<(k-)))){
int p = u|(<<(k-));
int q = v|<<(k-);
dfs2(i , p , q , cnt- , k-);
}
if(!(v&(<<(k-))) && !(u&(<<k))){
int p = u|(<<k);
int q = v|(<<(k-));
dfs2(i , p , q , cnt- , k-);
}
}
if(!(u&(<<k)) && !(v&(<<k))){
int p = u|(<<k);
int q = v|(<<k);
dfs2(i , p , q , cnt- , k-);
}
dfs2(i , u , v , cnt , k-);
} int main()
{
// freopen("a.in" , "r" , stdin);
int n , m;
while(scanf("%d%d" , &n , &m) != EOF)
{
for(int i= ; i<=n ; i++){
state[i] = ;
scanf("%s" , str);
for(int j= ; j< ; j++){
int t = str[j]-'';
state[i] = state[i]*+t;
}
} memset(dp , 0x3f , sizeof(dp));
dp[][state[]] = cnt_0(state[]);
dfs1( , state[] , dp[][state[]] , ); for(int i= ; i<=n ; i++){
for(int p= ; p< ; p++){
if(dp[i-][p] <INF){
// cout<<"state : i: "<<i<<" p: "<<p<<" "<<dp[i-1][p]+cnt_0(state[i])<<endl;
dfs2(i , state[i] , p , dp[i-][p]+cnt_0(state[i]) , );
}
}
}
int minn = INF;
for(int i= ; i< ; i++)
minn = min(minn , dp[n][i]);
// cout<<minn<<endl;
printf("%s\n" , minn<=m?"YES":"NO");
}
return ;
}
HDU 2442 方格填充
通过所给的5种形式的木块无覆盖填充n*m的方格,问最多有多少方格被填充
#include <iostream>
#include <cstdio>
#include <cstring> using namespace std; const int N = <<;
int dp[][N][N]; void dfs(int i , int w , int v , int u , int val , int k)
{
if(k<){
dp[i][v][u] = max(dp[i][v][u] , val);
return;
}
if(k>=){
if(!(w&(<<(k-))) && !(v&(<<(k-))) && !(u&(<<(k-))))
dfs(i , w|(<<(k-)) , v|(<<(k-)) , u|(<<(k-)) , val+ , k-);
if(!(v&(<<(k-))) && !(u&(<<(k-))))
dfs(i , w , v|(<<(k-)) , u|(<<(k-)) , val+ , k-);
if(!(v&(<<(k-))) && !(u&(<<k)))
dfs(i , w , v|(<<(k-)) , u|(<<k) , val+ , k-);
}
if(k>=){
if(!(w&(<<k)) && !(v&(<<(k-))) && !(u&(<<k)))
dfs(i , w|(<<k) , v|(<<(k-)) , u|(<<k) , val+ , k-);
if(!(w&(<<(k-))) && !(v&(<<k)) && !(u&(<<k)))
dfs(i , w|(<<(k-)) , v|(<<k) , u|(<<k) , val+ , k-);
}
dfs(i , w , v , u , val , k-);
} int main()
{
// freopen("a.in" , "r" , stdin);
int n,m;
while(scanf("%d%d" , &n , &m) == )
{
memset(dp , - , sizeof(dp));
dp[][(<<m)-][] = ;
for(int i= ; i<=n ; i++){
for(int w= ; w<(<<m) ; w++){
for(int v= ; v<(<<m) ; v++){
if(dp[i-][w][v]>=) dfs(i , w , v , , dp[i-][w][v] , m-);
}
}
}
int ans = ;
for(int v= ; v<(<<m) ; v++)
for(int u= ; u<(<<m) ; u++)
ans = max(ans , dp[n][v][u]);
printf("%d\n" , ans);
}
return ;
}
状态压缩DP总结的更多相关文章
- hoj2662 状态压缩dp
Pieces Assignment My Tags (Edit) Source : zhouguyue Time limit : 1 sec Memory limit : 64 M S ...
- POJ 3254 Corn Fields(状态压缩DP)
Corn Fields Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4739 Accepted: 2506 Descr ...
- [知识点]状态压缩DP
// 此博文为迁移而来,写于2015年7月15日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w6jf.html 1.前 ...
- HDU-4529 郑厂长系列故事——N骑士问题 状态压缩DP
题意:给定一个合法的八皇后棋盘,现在给定1-10个骑士,问这些骑士不能够相互攻击的拜访方式有多少种. 分析:一开始想着搜索写,发现该题和八皇后不同,八皇后每一行只能够摆放一个棋子,因此搜索收敛的很快, ...
- DP大作战—状态压缩dp
题目描述 阿姆斯特朗回旋加速式阿姆斯特朗炮是一种非常厉害的武器,这种武器可以毁灭自身同行同列两个单位范围内的所有其他单位(其实就是十字型),听起来比红警里面的法国巨炮可是厉害多了.现在,零崎要在地图上 ...
- 状态压缩dp问题
问题:Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Ev ...
- BZOJ-1226 学校食堂Dining 状态压缩DP
1226: [SDOI2009]学校食堂Dining Time Limit: 10 Sec Memory Limit: 259 MB Submit: 588 Solved: 360 [Submit][ ...
- Marriage Ceremonies(状态压缩dp)
Marriage Ceremonies Time Limit:2000MS Memory Limit:32768KB 64bit IO Format:%lld & %llu ...
- HDU 1074 (状态压缩DP)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1074 题目大意:有N个作业(N<=15),每个作业需耗时,有一个截止期限.超期多少天就要扣多少 ...
- HDU 4511 (AC自动机+状态压缩DP)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2-> ...
随机推荐
- HTTP/0.9、HTTP/1.0、HTTP/1.1、HTTP/2 历史演变和设计思路(详)*
HTTP 协议是互联网的基础协议,也是网页开发的必备知识,最新版本 HTTP/2 更是让它成为技术热点. 本文介绍 HTTP 协议的历史演变和设计思路. 一.HTTP/0.9 HTTP 是基于 TCP ...
- js学习笔记-事件委托
通过事件委托,你可以把事件处理器绑定到父元素上,避免了把事件处理器添加到多个子级元素上.从而优化性能. 事件代理用到了事件冒泡和目标元素.而任何一个元素的目标元素都是一开始的那个元素. 这里首先要注意 ...
- U9249 【模板】BSGS
题目描述 给定a,b,p,求最小的非负整数x 满足a^x≡b(mod p) 若无解 请输出“orz” 输入输出格式 输入格式: 三个整数,分别为a,b,p 输出格式: 满足条件的非负整数x 输入输出样 ...
- TCP/UDP套接字 java socket编程实例
网络协议七层结构: 什么是Socket? socket(套接字)是两个程序之间通过双向信道进行数据交换的端,可以理解为接口.使用socket编程也称为网络编程,socket只是接口并不是网络通信协议. ...
- jmeter 连接 sqlite 进行压力测试
- Mysql基本操作、C++Mysql简单应用、PythonMysql简单应用
MySql基本操作 -- 当指定名称的数据库不存在时创建它并且指定使用的字符集和排序方式 CREATE DATABASE IF NOT EXISTS db_name CHARACTER SET UTF ...
- SpringBoot 快速开发框架
学习资源:https://ke.qq.com/course/260513(这是Springboot升级版本教程,里面还有一个初级版本的) 1.第一个测试程序,那个覆盖方法加上@Override会报错, ...
- charset - 设置 G0/G1 字符集槽中的一个的 ACM
总览 (SYNOPSIS) charset [-v] G0|G1 [cp437|iso01|vt100|user|<acm_name>] 描述 (DESCRIPTION) linux 终端 ...
- vim 将文件所有行合并到一行
vim 将文件所有行合并到一行 在 Normal Mode下执行: ggvGJ gg 用于跳到行首 v 转换成 visual 模式 G 跳到最后一行 J 合并行
- QT5:先导篇 正则表达式
一.简介 使用正则表达式可以快速完成处理字符串的一些操作,如验证 查找 替换和分割 Qt的QRegExp类是正则表达式的表示类,它基于Perl的正则表达式语言 正则表达式由表达式(expression ...