状态压缩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.前 ...
随机推荐
- ruby语言仅仅是昙花一现
Ruby语言本身存在非常久了,在国内一直没火过.非常多人仅仅是知道有这样的语言,会的人少之又少.不论什么一种语言坚持十来年的发展,变得越来越好,一定有它不平常的地方.不能任意的去比較语言本身的好与坏. ...
- OpenJDK1.8.0 源码解析————HashMap的实现(一)
HashMap是Java Collection Framework 的重要成员之一.HashMap是基于哈希表的 Map 接口的实现,此实现提供所有可选的映射操作,映射是以键值对的形式映射:key-v ...
- Delphi主窗口任务栏菜单的问题(转发WM_SYSCOMMAND到Application)
Delphi的VCL框架在创建应用时TApplication是一个自动创建的隐藏窗口,其它创建的窗口是自动以该窗口为窗口,这就导致创始的主窗口在任务栏的系统菜单只有三项,只要在主窗口的Create事件 ...
- ThinkPhp学习05
原文:ThinkPhp学习05 一.ThinkPHP 3 的CURD介绍 (了解)二.ThinkPHP 3 读取数据 (重点) 对数据的读取 Read $m=new Model('User') ...
- XMPP协议简介
XMPP(息处理现场协议)是基于可扩展标记语言(XML)的协议.它用于即时消息(IM)以及在线现场探測.XMPP协议採用的是client-server架构,全部从一个client发到还有一个clien ...
- hdu3790最短路径问题 (用优先队列实现的)
Problem Description 给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的. Inp ...
- 如何在cocos2d项目中enable ARC
如何在cocos2d项目中enable ARC 基本思想就是不支持ARC的代码用和支持ARC的分开,通过xcode中设置编译选项,让支持和不支持ARC的代码共存. cocos2d是ios app开发中 ...
- 安装了VS2010 sp1 后再安装ASP.NET MVC 3.0的问题(Final Result: Installation failed with error code: (0x80070643), "安装时发生严重错误 " (Ela)
原文:安装了VS2010 sp1 后再安装ASP.NET MVC 3.0的问题(Final Result: Installation failed with error code: (0x800706 ...
- 福利 城市名的python list
["上海","北京","北京市","朝阳","朝阳区","海淀","元 ...
- Spark SQL 初步
已经Spark Submit 2013哪里有介绍Spark SQL.就在很多人都介绍Catalyst查询优化框架.经过一年的发展后,.今年Spark Submit 2014在.Databricks放弃 ...