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 包括多 ...
随机推荐
- [Swift]Swift的常用内置函数
内置函数:在Swift中不需要导入任何模块(如UIKit等)或者引用任何类就可以使用的函数.Swift预先定义的函数//快捷键Control+⌘+Space来开启Emoji字符输入 1.断言asser ...
- redis 学习笔记(一)
redis 基本类型 String 基本操作: GET 获取存储在给定键中的值 SET 设置存储在给定键中的值 DEL 删除存储在给定键中的值 List 基本操作: LPUSH/RPUSH 从左/右推 ...
- js高级程序设计 笔记 --- 表单
一,基础知识 在html中,表单是form元素,而在js中,表单对应的是HTMLFormElement类型,继承自HTMLElement,其独特的属性和方法有(常见): action:接收请求的URL ...
- jquery加载单文件vue组件
/**注册组件 */ function registerComponent(name){ dm[name] = {}; Vue.component(name + '-component', funct ...
- PIE SDK组件式开发综合运用示例
1. 功能概述 关于PIE SDK的功能开发,在我们的博客上已经分门别类的进行了展示,点击PIESat博客就可以访问,为了初学者入门,本章节将对从PIE SDK组件式二次开发如何搭建界面.如何综合开发 ...
- 通过shell处理多行数据
### 源文件 cat > tmpb <<'EOF' dbname:db_a,start_time::: query_end_time:::,query_total_time:,da ...
- UNIX SHELL基础知识总结(一)
1. Unix常目录结构与作用: 2. 基本命令: $echo $date $who $who am i 3. 创建文件的几种方式: A. touch FileName 创建空文件 B. > ...
- Git创建版本库和添加文件
创建版本库: 首先新建一个目录,然后通过 $ git init命令把这个目录变成Git可管理的仓库,例如: 在"C:\AmyPersonal\AmyGit"路径下新建文件夹Git1 ...
- Longest palindrome subsequence
A palindrome is a nonempty string over some alphabet that reads the same forwardand backward. Exampl ...
- opencv-python 读入带有中文的图片路径
windows 下读入带有中文的图片路径使用cv2.imread() 不能读入.使用如下代码可以. def cv_imread(filePath): cv_img = cv2.imdecode(np. ...