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 包括多 ...
随机推荐
- 使用 Git 进行版本控制
使用 Git 进行版本控制 版本控制软件让你能够拍摄处于可行状态的项目的快照.修改项目(如实现新功能)后,如果项目不能正常运行,可恢复到前一个可行状态. 通过使用版本控制软件,你可以无忧无虑地改进项目 ...
- Windows下使用DOS命令进入MySQL数据库
先要配置环境变量 MYSQL_HOME : D:\mysql-8.0.11-winx64 Path:%MYSQL_HOME%\bin 1)新建MYSQL_HOME变量,并配置:C:\Program F ...
- codis__数据迁移和伸缩容
数据迁移命令 注意点:是迁移到某个 redis-group 而不是某个redis-servers 实例 伸缩容用法 redis 内存等不够用时 增容 : 增加redis-group, 然后迁移使用上 ...
- NFS共享服务
一.网络文件系统共享服务 NFS( Network File System,网络文件系统 )是一种基于TCP/IP传输的网络文件系统协议,最初由SUN公司开发,通过使用NFS协议,客户机可以像访问本地 ...
- ajax方法参数详解与$.each()和jquery里面each方法的区别
JQuery中$.ajax()方法参数详解 url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. type: 要求为String类型的参数,请求方式(post或get)默认为g ...
- 9012年,我终于找到了Pypi稳定的源....
前情提要 近日听说华为也做了一个华为开源镜像站所以去体验了一波然后此处做个总结吧. 既然是体验当然是从直观的第一感觉UI开始说起. 界面体验 一点进去挺好的界面很清爽. 最难能可贵的是终于没有再使用列 ...
- [原创] Laravel 启动流程
目录 1. 程序启动准备 1.1 容器基础配置 1.2 核心类绑定 1.3 实例化 Http 核心类 2. 请求实例化 3. 请求处理 3.1 请求处理环境初始化 1. 环境监测 \Illuminat ...
- 大数据-hadoop HA集群搭建
一.安装hadoop.HA及配置journalnode 实现namenode HA 实现resourcemanager HA namenode节点之间通过journalnode同步元数据 首先下载需要 ...
- 接口自动化 之 unittest+ddt+openpyxl 综合
前面写过python 之 unittest初探 和 python 之 unittest+ddt 两篇文章.在之前的文章中,写过可以再次优化.今天写第三篇的目的,就是在原有基础上,基于 openpyxl ...
- POJ_2886 Who Gets the Most Candies? 【二分+树状数组】
一.题目 POJ2886 二.分析 这个题目吧,开始没读懂,做的时候也没懂,WA的时候懂了.假设是第p个出圈的人有一个对应的因子个数$F(p)$,那么,题目求的就是这个$F(p)$最大的对应的人. 1 ...