hdu 1565 方格取数(1) 状态压缩dp
方格取数(1)
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3848 Accepted Submission(s): 1473
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std; int a[][];
int dp1[<<],before[<<],now[<<]; void prepare(int i,int n)//预处理
{
int j,k,s;
k=<<n;
for(j=; j<k; j++)
{
dp1[j]=;
for(s=; s<=n; s++)
{
if( (j&(<<(s-))) == (<<(s-)) )//包含了这个数字
dp1[j]=dp1[j]+a[i][s];
}
}
}
bool panduan(int b,int n)
{
int i,x;
x=;
for(i=; i<n; i++)
{
if( (x&b) == x) return false;
x=x<<;
}
return true;
}
int main()
{
int n;
int i,j,s,k,hxl;
scanf("%d",&n);
{
for(i=; i<=n; i++)
for(j=; j<=n; j++)
scanf("%d",&a[i][j]);
memset(now,,sizeof(now));
memset(before,,sizeof(before));
k=<<n;
for(i=; i<=n; i++)
{
prepare(i,n);
for(j=; j<k; j++)
if(panduan(j,n))
{
hxl=;
for(s=; s<k; s++)
{
if( (s&j)> ) continue;
if(before[s]>hxl)
hxl=before[s];
}
dp1[j]=dp1[j]+hxl;
}
for(j=; j<k; j++)
{
now[j]=dp1[j];
before[j]=now[j];
}
}
hxl=;
for(i=; i<k; i++)
if(now[i]>hxl) hxl=now[i]; printf("%d\n",hxl);
}
return ;
}
优化:
很多地方可以优化。
1.其实,可以预处理相邻的情况。不要每一次都判断。就像打表一样。//怎么处理的呢?具体看一下代码。
2.预处理相邻的情况后,发现,1<<20的数组,满足条件的只有17711种,这样的话,优化就巨大了。
3.滚动数组。
我的代码,还是不够优化的,960ms
#include<stdio.h>
#include<stdlib.h>
#include<string.h> int a[][];
int state[],len;
int dp[<<],befor[<<]; void make_init()//预处理,所以的状态
{
int i,k;
k=<<;
len=;
for(i=;i<k;i++)
{
if( (i&(i<<))> ) continue;
else state[len++]=i;
}
}
void prepare(int r,int n)//处理每一行的dp值.
{
int i,j,k,ans,x;
k=<<n; for(j=;state[j]<k;j++)
{
i=state[j];
dp[i]=;
x=i;
ans=;
while(x)
{
if(x&) dp[i]=dp[i]+a[r][ans];
ans++;
x=x>>;
}
}
} int main()
{
int n;
int i,j,k,s,hxl;
make_init();
while(scanf("%d",&n)>)
{
for(i=;i<=n;i++)
for(j=;j<=n;j++)
scanf("%d",&a[i][j]); k=<<n;
memset(befor,,sizeof(befor));
for(i=;i<=n;i++) //枚举每一行
{
prepare(i,n);
for(j=;state[j]<k;j++)//枚举每一种 有效 状态
{
hxl=;
for(s=;state[s]<k;s++)//上一行的有效状态
{
if( (state[j]&state[s]) >) continue;//没有冲突
if(befor[state[s]]>hxl)
hxl=befor[state[s]];
}
dp[state[j]]=dp[state[j]]+hxl;
}
for(j=;state[j]<k;j++)
{
befor[state[j]]=dp[state[j]];
}
}
hxl=;
for(i=;state[i]<k;i++)
if(hxl<befor[state[i]]) hxl=befor[state[i]];
printf("%d\n",hxl);
}
return ;
}
进一步的优化:
看了一下,别人的博客,看到一个很别人开的数组是很小的。why?
我开的dp数组是 dp[1<<22],其实只要开dp[17715];和状态state[17715 ]一样就可以了.
为什么可以呢?
简单说明一下:原来的方法,是和最原始的位置是一一对应,所以,很好理解。
但是,有很多的空间是浪费的。
现在是对应状态一一对应,就是这样。这样数组开的就小很多了。而且速度快一些。
921ms --> 486 ms
#include<stdio.h>
#include<stdlib.h>
#include<string.h> int a[][];
int state[],len;
int dp[],befor[]; void make_init()//预处理,所以的状态
{
int i,k;
k=<<;
len=;
for(i=;i<k;i++)
{
if( (i&(i<<))> ) continue;
else state[len++]=i;
}
}
void prepare(int r,int n)//处理每一行的dp值.
{
int j,k,ans,x;
k=<<n; memset(dp,,sizeof(dp));
for(j=;state[j]<k;j++)
{
x=state[j];
ans=;
while(x)
{
if(x&) dp[j]=dp[j]+a[r][ans];//!!!哈哈。
ans++;
x=x>>;
}
}
} int main()
{
int n;
int i,j,k,s,hxl;
make_init();
while(scanf("%d",&n)>)
{
for(i=;i<=n;i++)
for(j=;j<=n;j++)
scanf("%d",&a[i][j]); k=<<n;
memset(befor,,sizeof(befor));
for(i=;i<=n;i++) //枚举每一行
{
prepare(i,n);
for(j=;state[j]<k;j++)//枚举每一种 有效 状态
{
hxl=;
for(s=;state[s]<k;s++)//上一行的有效状态
{
if( (state[j]&state[s]) >) continue;//没有冲突
if(befor[s]>hxl)
hxl=befor[s];
}
dp[j]=dp[j]+hxl;
}
for(j=;state[j]<k;j++)
{
befor[j]=dp[j];
}
}
hxl=;
for(i=;state[i]<k;i++)
if(hxl<befor[i]) hxl=befor[i];
printf("%d\n",hxl);
}
return ;
}
hdu 1565 方格取数(1) 状态压缩dp的更多相关文章
- HDU 1565 - 方格取数(1) - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]
题目链接:https://cn.vjudge.net/problem/HDU-1565 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32 ...
- HDU1565 方格取数(1)(状态压缩dp)
题目链接. 分析: 说这题是状态压缩dp,其实不是,怎么说呢,题目数据太水了,所以就过了.手动输入n=20的情况,超时.正解是网络流,不太会. A这题时有个细节错了,是dp[i][j]还是dp[i][ ...
- 网络流(最大流) HDU 1565 方格取数(1) HDU 1569 方格取数(2)
HDU 1565 方格取数(1) 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的 ...
- HDU 1565 方格取数(1) 轮廓线dp
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others) ...
- hdu 1565 方格取数(1)(状态压缩dp)
方格取数(1) Time Limit: 10000/5000 MS (J ...
- hdu 2167 方格取数 【状压dp】(经典)
<题目链接> 题目大意: 给出一些数字组成的n*n阶矩阵,这些数字都在[10,99]内,并且这个矩阵的 3<=n<=15,从这个矩阵中随机取出一些数字,在取完某个数字后,该数 ...
- HDU 1565 方格取数(简单状态压缩DP)
http://acm.hdu.edu.cn/showproblem.php?pid=1565 对于每一个数,取或者不取,用0表示不取,1表示取,那么对于每一行的状态,就可以用一个二进制的数来表示.比如 ...
- HDU 1565 方格取数(1)(最大点权独立集)
http://acm.hdu.edu.cn/showproblem.php?pid=1565 题意: 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格 ...
- HDU 1565 方格取数 状压dp
题目: 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多 ...
随机推荐
- HDU6184【Counting Stars】(三元环计数)
题面 传送门 给出一张无向图,求 \(4\) 个点构成两个有公共边的三元环的方案数. 题解 orz余奶奶,orz zzk 首先,如果我们知道经过每条边的三元环个数\(cnt_i\),那么答案就是\(\ ...
- P3366 (模板)最小生成树
2019-01-30 最小生成树基本算法 定义: 给定一个边带权的无向图G=(V,E),n=|V|,m=|E|,由V中全部n个定点和E中n-1条边构成的无向连通子图被称为G的一颗生成树. 边的权值之和 ...
- 2016级算法第二次上机-B.Bamboo的OS实验
Bamboo的OS实验 分析 首先理解题意,要完成不同数量的不同命令,但是完成相同的命令之间必须有n个间隔,为使得时间最短,自然优先用其他命令来填充这n分钟的时间,由于数量少的命令可以用来填充空隙,所 ...
- Object类和包装类的一些方法
一.instanceof关键字的使用: a instanceof A:判断对象a是否是类A的实例.如果是,返回true:如果不是,返回false. 使用场景:为了避免在向下转型时出现ClassCast ...
- 实验吧之deeeeeeaaaaaadbeeeeeeeeeef-200
题目中提示说“图片是正确的吗”,赶紧打开图片,图片显示正常,没啥毛病,那就放到winhex里面,好像它的十六进制格式也蛮标准的,然后它的文本区域有个iphone,这个梗我也是百度才知道的: winhe ...
- Oracle 第三方管理工具整理
Oracle 第三方管理工具整理 1.OB(SI Object Browser) 官方网址: http://www.ctdw.com.cn说明:小软件大功能,个人最爱它的数据库导入.导出功能,一键导入 ...
- 233 Matrix(矩阵快速幂+思维)
In our daily life we often use 233 to express our feelings. Actually, we may say 2333, 23333, or 233 ...
- WebFrom页面绑定数据过于冗长的处理方法
嘛 这个是当时写完东西之后 功能没什么问题 但是由于页面绑定的数据太长 破坏了整体的样式(对于本人来说 样式就是浮云....) 所以测试就跟我说必须弄好看点 于是乎 我就找到了下面这种方法 因为我这 ...
- nginx(三)-动静分离
什么叫动静分离 所谓动静分离就是说我们的图片,css,js之类的文件都交给nginx来处理,nginx处理不了的,比如jsp就交给tomcat来处理. 有人计算过,nginx代理处理静态请求远远优于t ...
- Linux I2C驱动程序设计
1. Linux I2C子系统架构 (1)I2C核心(I2C-Core):I2C 总线和I2C 设备驱动的中间枢纽,它提供了I2C 总线驱动和设备驱动的注册.注销方法等 (2)I2C控制器驱动(ada ...