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 包括多 ...
随机推荐
- [ActionScript 3.0] AS3实现3D旋转
package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Display ...
- python学习笔记之使用threading模块实现多线程(转)
综述 Python这门解释性语言也有专门的线程模型,Python虚拟机使用GIL(Global Interpreter Lock,全局解释器锁)来互斥线程对共享资源的访问,但暂时无法利用多处理器的优势 ...
- try语句块和异常处理
在C++中,异常处理包括: · throw表达式(throw expression) 异常检测部分使用throw表达式来表示它遇到了无法处理的问题.throw表达式抛出一个异常并把控制权转移到能处理该 ...
- 高阶篇:4.1.2.3)产品零件级别的QFDII
本章目的:介绍产品零件级别的QFDII编写方法. 1.前言 这章接前面部件级别的QFDII. 产品零件级别的QFDII,其实就是将零件QFDII所得到的设计要求,进一步分配零件的特征(Part Cha ...
- 小蒟蒻的垃圾emacs配置
(global-set-key [f9] 'compile-file) (global-set-key [f10] 'gud-gdb) (global-set-key (kbd "C-s&q ...
- 彻底成功配置Maven和Eclipse集成
这篇文章是分享给还在苦苦挣扎eclipse和Maven环境配置的同志,让其少走弯路,话不多说,直接开始吧 环境出问题一是配置没有配置好,二是各个部分可能出现兼容问题,导致错误,综上,我选择了一个切实可 ...
- python四则运算2.0
github项目地址: https://github.com/kongkalong/python PSP 预估耗时(分钟) Planning .Estimate 48*60 Development . ...
- Vue项目中使用HighChart
记:初次在Vue项目中使用 HighChart 的时候要走的坑 感谢这位哥们的思路 传送门 Vue-cli项目使用 npm install highcharts --save 让我们看看 highch ...
- netty总结
eventLoopGroup中创建各个eventLoop处理线程,各个pipeLineHandler处理childEvent时是在自己的线程中, 全异步
- pandas中获取数据框的行、列数
获取数据框的行.列数 # 获取行数 df.shape[0] # 获取行数 len(df) # 获取列数 df.shape[1]