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 包括多 ...
随机推荐
- python 序列结构-列表,元组,字典,字符串,集合
列表 """ name_list.__add__( name_list.__getslice__( name_list.__new__( name_list.append ...
- sizeWithFont:的替代方法
sizeWithFont:的替代方法 -(CGFloat)changeStationWidth:(NSString *)string{ UIFont * textFont = [UIFont syst ...
- jmeter之jtl文件解析(生成测试报告)
我们知道命令行的方式执行完成jmeter后,会生成jtl文件,里面打开后就是一行行的测试结果, <httpSample t="1" lt="1" ts=& ...
- iOS 发送位置消息
发送地理位置在社交应用里面是很常用的需求.最近也需要在自己的应用里面加入这个功能 首先我们需要获取自己的地理位置,这里用到 CLLocationManager 这个类,调用如下代码 locationM ...
- 通过cookie绕过验证码登录
在我们做自动化的时候碰到一些比较难破解的验证码时是非常头疼的,一般来说最好的办法就是让开发屏蔽,这样最有益身心健康. 那么今天我介绍的这个方法也挺简单的,就是通过添加cookie的方式绕过验证码直接登 ...
- [转]IOS应用程序多语言本地化解决方案
最近要对一款游戏进行多语言本地化,在网上找了一些方案,加上自己的一点点想法整理出一套方案和大家分享! 多语言在应用程序中一般有两种做法:一.程序中提供给用户自己选择的机会:二.根据当前用户当前移动设备 ...
- JavaWeb学习笔记(二十二)—— 过滤器filter
一.什么是过滤器 过滤器filter是JavaWeb三大组件之一,它与Servlet很相似!不过过滤器是用来拦截请求的,而不是处理请求的.WEB开发人员通过Filter技术,对web服务器管理的所有w ...
- 使用FFmpeg进行视频抽取音频,之后进行语音识别转为文字
1.首先需要下载FFmpeg: 2.Gradle依赖 def void forceVersion(details, group, version) { if (details.requested.gr ...
- 2018 ICPC Asia Jakarta Regional Contest
题目传送门 题号 A B C D E F G H I J K L 状态 Ο . . Ο . . Ø Ø Ø Ø . Ο Ο:当场 Ø:已补 . : 待补 A. Edit Distance Thin ...
- More Effective C++ 35个改善方法
美·Scott Meyers 侯捷 More Exceptional C++: 40 New Engineering Puzzles, Programming Problems, and Soluti ...