状态压缩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-> ...
随机推荐
- ACM_不知所措的统计员
Problem Description: GDUFE-GAME完美结束,按照惯例,会有一篇报道,描述活动期间的盛况,因此相关人员找到负责统计的ASDF,但是ASDF只知道第i个人在S_i时进场,在E_ ...
- MyEclipse去除不必要的validation
MyEclipse在构建项目时去除不必要的Valication可以加快构建速度. 操作: Window->Perferences->MyEclipse->Validation 在Va ...
- java问题收集
2014-10-27 构造器最好保留一个无参的,否则一些框架调用初始化时,会报错 星期三,2013年11月6日 volatile关键字 : 1. 与synchronized几乎相同,但是vol ...
- TRUNCATE TABLE 与 DELETE (转)
TRUNCATE TABLE 删除表中的所有行,而不记录单个行删除操作.TRUNCATE TABLE 与没有 WHERE 子句的 DELETE 语句类似:但是,TRUNCATE TABLE 速度更快, ...
- 213 House Robber II 打家劫舍 II
注意事项: 这是 打家劫舍 的延伸.在上次盗窃完一条街道之后,窃贼又转到了一个新的地方,这样他就不会引起太多注意.这一次,这个地方的所有房屋都围成一圈.这意味着第一个房子是最后一个是紧挨着的.同时,这 ...
- AJPFX总结泛型概念和使用
泛型泛型(generic)概述和基本使用 泛型把明确数据类型的操作放到创建对象或者调用方法的时候再明确. J ...
- div里面整齐的字体样式,所有浏览器都兼容
<div id="wenda"> <div class="table_wd" > <div class="tr1&quo ...
- poj2718 Smallest Difference
思路: 暴力乱搞. 实现: #include <iostream> #include <cstdio> #include <sstream> #include &l ...
- spring.net应用
经过一段时间的调试,终于把spring.net中关于aop的方面给做个了一个比较完整的Demo.包含异常日志和性能日志.spring.net和log4net配置. http://files.cnblo ...
- iOS---数据离线缓存
离线缓存 为了用户的体验,不需要每次打开App都加载新数据,或者重新请求数据,因此需要把每次浏览的数据保存起来,当下次打开软件时,首先从沙盒中加载数据:或者当软件未联网时,也只能从沙盒中加载旧数据. ...