状态压缩dp(hdu2167,poj2411)
hdu2167 http://acm.hdu.edu.cn/showproblem.php?pid=2167
给定一个N*N的板子,里面有N*N个数字,选中一些数字,使得和最大
要求任意两个选中的数字不相邻,相邻包括上下,左右和对角线相邻。
由于N<=15,用程序判断了一下,每一行的有效状态<1600个,如果记录这些状态,然后每一行枚举当前行的上一行的状态那么极端下有1600*1600*15的复杂度,TLE
所以卡在这里很久,想不到怎么优化。 然后看了别人的代码知道了用邻接表存储哪两个状态是相容的。这样就不用枚举那么多了。所以就过了。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <sstream>
using namespace std;
int matrix[][];
int dp[<<][],situation[],bit[],head[],e;
struct node
{
int v,next;
}g[];;
int max(const int &a, const int &b)
{
return a < b ? b : a;
} void addEdge(int u, int v)
{
g[e].v = v;
g[e].next = head[u];
head[u] = e++;
}
int count(int i, int ss, int n)//计算状体第i行的状态s所取的数的和
{
int ret = ;
int j = ;
for(j=; j<n; ++j)
{
if(bit[j] & ss)
ret += matrix[i][j];
}
return ret;
}
bool check(int s, int ss,int n)//检查s和ss是否可容
{ if(s&ss) return false;
if((s<<)&ss) return false;
if((s>>)&ss) return false;
return true;
}
int main()
{
int n,i,j,m,s,ss;
char str[];
bit[i=] = ;
for(i=; i<; ++i)
bit[i] = bit[i-]<<;
m = <<;
for(i=,j=; i<m; ++i)
if(!(i&(i<<)))//求出有效的状态
situation[j++]= i;
while(gets(str))
{
memset(dp,,sizeof(dp));
e = ;
memset(head,-,sizeof(head));
n = ;
do
{
j = ;
stringstream scin(str);
while(scin>>matrix[n][j]) j++;
n++;
gets(str);
if(str[]=='\0') break; }while(true);
m = <<n;
for(i=;situation[i]<m; ++i)//判断哪两个状体相容,然后用邻接表存储
for(j=; situation[j]<m; ++j)
if(check(situation[i],situation[j],n))
addEdge(i,j);
for(i=; situation[i]<m; ++i)
dp[situation[i]][] = count(,situation[i],n);
for(i=; i<n; ++i)
for(s=;situation[s]<m; ++s)
{
for(j=head[s];j!=-;j=g[j].next)
{
dp[situation[g[j].v]][i] = max(dp[situation[g[j].v]][i],dp[situation[s]][i-]+count(i,situation[g[j].v],n));
}
}
int ans = ;
for(i=; situation[i]<m; ++i)
{
ans = max(ans,dp[situation[i]][n-]);
}
printf("%d\n",ans);
}
return ;
}
poj2411 http://poj.org/problem?id=2411
给定一个N*M的矩形,用1*2的矩阵填充满,问有多少种填充的方法。 N,M<=11
状态压缩dp,时间复杂度是N*(1<<M)*(1<<M),可以使用邻接表存储,哪些状态是相容的,这样子,就不用枚举所有的状态了。
状态是如何转移的呢?
首先第一行的状态必须是:如果有1,那么必须有连续的两个1.即不能有单独的一个1.
这样子是为了,第二行如果竖着放,那么就可以填充第一行的空缺。
怎么判断当前行的状态和上一行的状态不冲突的?详见bool check(int s, int ss)函数注释
#include <stdio.h>
#include <string.h>
#define LL __int64
int n,m;
int e,head[];
LL dp[<<][];
struct node
{
int v,next;
}g[]; void addEdge(int a, int b)
{
g[e].v = b;
g[e].next = head[a];
head[a] = e++;
}
void swap(int &a, int &b)
{
int t = a;
a = b;
b = t;
}
bool check(int s)
{
while(s)
{
if( (s&) && ((s>>)&))
s>>=;
else if( (s&) && !((s>>)&))
return false;
else if(!(s&))
s>>=; }
return true;
}
bool check(int s, int ss)
{
for(int i=; i<m; ++i)
{
if(!(s&) && !(ss&)) return false;//上一行该位置为0,那么这一行该位置应该竖着放,否则不相容
else if(!(s&)&&(ss&))
{
s>>=;ss>>=;continue;//上一行为0,这一行竖着放
}
else if((s&)&&!(ss&))
{
s>>=;ss>>=;continue;//上一行该位置为1,这一行可以不放
}
else if((s&)&&(ss&))//上一行的该位置和这一行的该位置为1,那么这行的矩形是横着放
{
s>>=,ss>>=;i++;
if((s&)&&(ss&)) //即下一个位置,上一行和这一行都必须为1
{
s>>=;ss>>=;continue;
}
else return false;
}
}
return true;
}
int main()
{
int s,ss,t,i,j;
LL ans;
while(scanf("%d%d",&n,&m),n)
{
memset(dp,,sizeof(dp));
if(n<m) swap(n,m);
ans = ;
t = <<m;
memset(head,-,sizeof(head));
e = ;
for(s=; s<t; ++s)
for(ss=; ss<t; ++ss)
if(check(s,ss))
addEdge(s,ss);
if((n*m)%==)
{
for(s=; s<t; ++s)
if(check(s))
dp[s][] = ;
for(i=; i<n; ++i)
for(s=; s<t; ++s)
for(j=head[s];j!=- && g[j].v<t;j=g[j].next)
dp[g[j].v][i] += dp[s][i-]; ans = dp[(<<m)-][n-];
}
printf("%I64d\n",ans);
}
return ;
}
状态压缩dp(hdu2167,poj2411)的更多相关文章
- HDU2167+状态压缩DP
状态压缩dp 详见代码 /* 状态压缩dp dp[ i ][ j ]:第i行j状态的最大和 dp[i][j] = max( dp[i-1][k]+sum[i][j] ); 题意:给定一个N*N的方格, ...
- DP大作战—状态压缩dp
题目描述 阿姆斯特朗回旋加速式阿姆斯特朗炮是一种非常厉害的武器,这种武器可以毁灭自身同行同列两个单位范围内的所有其他单位(其实就是十字型),听起来比红警里面的法国巨炮可是厉害多了.现在,零崎要在地图上 ...
- HDU1565+状态压缩dp
简单的压缩状态 dp /* 状态压缩dp 同hdu2167 利用滚动数组!! */ #include<stdio.h> #include<string.h> #include& ...
- SGU131 - Hardwood floor(状态压缩DP)
题目大意 给定一个N*M大小的矩形,要求你用1*2和2*2(缺个角)的砖块把矩形铺满(不能重叠),问总共有多少种铺法? 题解 受POJ2411的影响,怎么都没想到3,4,5,6这几种情况该怎么放置,看 ...
- HihoCoder第九周 状态压缩 二 与POJ2411总结
在此我向各位博友求助,特别想知道除了HihoCoder上面的结果要对1e9+7取余之外,这两道题还有什么其他的问题,都是骨牌覆盖问题,都是状态压缩+dp,为什么我能过poj2411的程序过不了Hiho ...
- 状态压缩DP(大佬写的很好,转来看)
奉上大佬博客 https://blog.csdn.net/accry/article/details/6607703 动态规划本来就很抽象,状态的设定和状态的转移都不好把握,而状态压缩的动态规划解决的 ...
- 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.前 ...
随机推荐
- OCA读书笔记(4) - 管理数据库实例
Objectives: •Start and stop the Oracle database and components •Use Oracle Enterprise Manager •Acces ...
- HDU4869:Turn the pokers(费马小定理+高速幂)
Problem Description During summer vacation,Alice stay at home for a long time, with nothing to do. S ...
- 第十七篇:实例分析(1)--初探WDDM驱动学习笔记(八)
第四篇(VidPN)中提到过MIRROR驱动. 在进入本篇的实际内容前, 带着好奇心, 想请教CSDN中的显卡驱动方面的大虾, 怎样才干把这个驱动玩起来, 这个驱动的作用是什么,等等, 敬请不吝赐教. ...
- jsonp和事件发布监听
模拟jsonp var id = 0; function JSONP(url,param,cb){ var callbackName = "json_" + id++; var a ...
- 检测用户是否具有administrator权限(OpenThreadToken,OpenProcessToken,GetTokenInformation,AllocateAndInitializeSid和EqualSid)
检测用户是否具有administrator权限const SECURITY_NT_AUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0 ...
- javascript --- 事件托付
javascript 之 事件托付 长处:1.提高性能(仅仅须要对父级进行操作,子节点相同会拥有其相关属性和方法) 2.对于新加入的事件.也让其拥有父级事件的属性 <!doctype html& ...
- 深刻:截获windows的消息并分析实例(DefWindowProc),以WM_NCHITTEST举例(Windows下每一个鼠标消息都是由 WM_NCHITTEST 消息产生的,这个消息的参数包含了鼠标位置的信息)
1,回调函数工作机制 回调函数由操作系统自动调用,回调函数的返回值当然也是返回给操作系统了. 2,截获操作系统发出的消息,截获到后,将另外一个消息返回给操作系统,已达到欺骗操作系统的目的. 下面还是以 ...
- java学习笔记04--数组
java学习笔记04--数组 数组复制的方法是使用System类提供的arraycopy()方法,其语法如下: System.arraycopy(Object src, int srcPos, Obj ...
- 慎得慌风 656ik67o
http://photo.163.com/q/7634581 http://photo.163.com/q/7634580 http://photo.163.com/q/7634577 http:// ...
- 有关于web server架构的一个小疑问
今天闲的时候trace route了yahoo和sina的域名,yahoo的如下: 1 1 ms 1 ms <1 ms 172.21.127.1 2 3 ms ...