Problem 1608 - Calculation
Time Limit: 500MS   Memory Limit: 65536KB    Total Submit: 311  Accepted: 82  Special Judge: No
Description
Today, Alice got her math homework again!
She had n integers, and she needed to divide them into several piles or one pile. For each pile, if the teacher could get Sby + or – operator, then Alice got 1 small red flower. Alice wanted to get as many flowers as possible. Could you help her? Just tell her the maximum number of flowers she could get.
Input
The input consists of several test cases. The first line consists of one integer T (T <= 100), meaning the number of test cases. The first line of each test cases consists of two integer n (n<=14), meaning the number of the integer, and S (0<= S<= 100000000), meaning the result which teacher wanted. The next line consists of n integer a1, a2, …, an (0<= ai <= 10000000). You should know a few cases that n is larger than 12.
Output
For each test case, output one line with one integer without any space.
Sample Input
2
5 5
1 2 3 4 5
5 5
1 2 3 8 8
Sample Output
3 2
题解:
题目让求a集合的元素通过加减能组成S的最大组数,每个数字只能用一次;
看到这个题目就想着用dfs搜索,再状压下用的位置;但是华丽丽的wa了;首先自己的处理不对,时间复杂度是4^n,也就是2^28,超时不说,还有就是自己的太暴力了,并不一定是最优解;最后问了学长,学长一眼看出了我的错误,然后我的思路就行不通了。。。学长说这个应该是状压dp;
第一发状压dp,思想是dfs找解,如果找到dp状压的位置是1;然后for循环找到1~1<<n的所有的子集,dp[i]=max(子集的最优解+对i的补集的最优解,dp[i]);
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int dp[ << ];
int a[];
int n, S;
void dfs(int i, int val, int cur){
if(i == n){
if(val == S){
dp[cur] = ;
}
return;
}
dfs(i + , val, cur);
dfs(i + , val + a[i], cur | ( << i));
dfs(i + , val - a[i], cur | ( << i));
}
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &S);
for(int i = ; i < n; i++){
scanf("%d", a + i);
}
fill(dp, dp + ( << n), );
dfs(, , );
for (int i = ; i < ( << n); i++){
for (int j = i & (i - ); j > ; j = i & (j - )){
dp[i] = max(dp[i], dp[j] + dp[j ^ i]);
//j是i的子集,j ^ i 是i的补集;
}
}
printf("%d\n", dp[( << n) - ]);
}
return ;
}

学长说还可以用中途对撞写,那样可以把dfs时间复杂度降到O(n*3^(n / 2)):

学长的中途对撞:

int d[ << ];
int a[];
int n, s; void MakeSum(const vector<int> &x, vector< pair<int, int> > &res) {
for (int i = ; i < ( << x.size()); ++i) {
int cur = ;
for (int j = ; j < x.size(); ++j) {
if (i >> j & ) cur -= x[j];
}
res.push_back(make_pair(cur, i));
for (int j = i; j > ; j = (j - ) & i) {
cur = ;
for (int k = ; k < x.size(); ++k) {
if (i >> k & ) {
if (j >> k & ) cur += x[k];
else cur -= x[k];
}
}
res.push_back(make_pair(cur, i));
}
}
sort(res.begin(), res.end());
} void Init() {
fill(d, d + ( << n), );
vector< pair<int, int> > left, right;
int mid = n / ;
MakeSum(vector<int>(a, a + mid), left);
MakeSum(vector<int>(a + mid, a + n), right);
for (int i = ; i < left.size(); ++i) {
int lo = lower_bound(right.begin(), right.end(), make_pair(s - left[i].first, -)) - right.begin();
int hi = upper_bound(right.begin(), right.end(), make_pair(s - left[i].first, << )) - right.begin();
for (int j = lo; j < hi; ++j) {
d[left[i].second | (right[j].second << mid)] = ;
}
}
} int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &s);
for (int i = ; i < n; ++i) {
scanf("%d", a + i);
}
Init();
for (int i = ; i < ( << n); ++i) {
for (int j = (i - ) & i; j > ; j = (j - ) & i) {
d[i] = max(d[i], d[j] + d[i ^ j]);
}
}
printf("%d\n", d[( << n) - ]);
}
return ;
}
 

Calculation(dfs+状压dp)的更多相关文章

  1. POJ 1321 棋盘问题(DFS & 状压DP)

    用DFS写当然很简单了,8!的复杂度,16MS搞定. 在Discuss里看到有同学用状态压缩DP来写,就学习了一下,果然很精妙呀. 状态转移分两种,当前行不加棋子,和加棋子.dp[i][j]中,i代表 ...

  2. CODEVS1358【DFS/状压DP】

    题目链接[http://codevs.cn/problem/1358/] 题意:这个游戏在一个有10*10个格子的棋盘上进行,初始时棋子位于左上角,终点为右下角,棋盘上每个格子内有一个0到9的数字,每 ...

  3. Atcoder Beginner Contest152F(DFS+状压DP)

    二维状压写成一维状压,省略加上第i条边这一维 #define HAVE_STRUCT_TIMESPEC #include<bits/stdc++.h> using namespace st ...

  4. 【62测试】【状压dp】【dfs序】【线段树】

    第一题: 给出一个长度不超过100只包含'B'和'R'的字符串,将其无限重复下去. 比如,BBRB则会形成 BBRBBBRBBBRB 现在给出一个区间[l,r]询问该区间内有多少个字符'B'(区间下标 ...

  5. BZOJ-1087 互不侵犯King 状压DP+DFS预处理

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MB Submit: 2337 Solved: 1366 [Submit][ ...

  6. UVaLive 6625 Diagrams & Tableaux (状压DP 或者 DFS暴力)

    题意:给一个的格子图,有 n 行单元格,每行有a[i]个格子,要求往格子中填1~m的数字,要求每个数字大于等于左边的数字,大于上边的数字,问有多少种填充方法. 析:感觉像个DP,但是不会啊...就想暴 ...

  7. HDU 4272 LianLianKan (状压DP+DFS)题解

    思路: 用状压DP+DFS遍历查找是否可行.假设一个数为x,那么他最远可以消去的点为x+9,因为x+1~x+4都能被他前面的点消去,所以我们将2进制的范围设为2^10,用0表示已经消去,1表示没有消去 ...

  8. 【题解】洛谷P3959 [NOIP2017TG] 宝藏(状压DP+DFS)

    洛谷P3959:https://www.luogu.org/problemnew/show/P3959 前言 NOIP2017时还很弱(现在也很弱 看出来是DP 但是并不会状压DP 现在看来思路并不复 ...

  9. bjtu 1846. Infinity的装备[状压dp+dfs/bfs]

    https://citel.bjtu.edu.cn/acm/oj/problem/1846 1846. Infinity的装备 时间限制 1000 ms 内存限制 64 MB 题目描述 “测试服终于下 ...

随机推荐

  1. NSSCanner 提取 指定 字符串

    /** *  从msg中提取指定的内容 * *  @param msg 字符串集合 * *  @return 从msg中提取指定的内容 */ -(NSString*)extractBodyFromMe ...

  2. SICP 习题 (1.9) 解题总结

    SICP 习题 1.9 开始针对“迭代计算过程”和“递归计算过程”,有关迭代计算过程和递归计算过程的内容在书中的1.2.1节有详细讨论,要完成习题1.9,必须完全吃透1.2.1节的内容,不然的话,即使 ...

  3. 细讲encodeURI和encodeURIComponent以及escape的区别与应用

    首先,我们都知道这三个东西都是用来编码的 先来说encodeURI()和encodeURIComponent() 这两个是在转换url时候用来编码解码用的. 有编码就会有解码, 解码就是decodeU ...

  4. ASP.NET 导出Excel文档

    System.IO.TextWriter writer = new System.IO.StreamWriter(Server.MapPath("/provprice.xls"), ...

  5. XtraReport改变纸张方向

    XtraReport纸张方向改变可以通过修改Landscape属性: Landscape=true 为横向输出 Landscape=false 为纵向输出

  6. 浏览器的Storage做缓存需要注意的地方

    使用浏览器的Storage来做缓存.如: window.sessionStorage.setItem("cache", $(data).stringify()) 需要注意以下几点: ...

  7. OpenCV——人脸检测

    OpenCV支持的目标检测的方法: 利用样本的Haar特征进行的分类器训练,得到的级联boosted分类器(Cascade Classification) 1.加载级联分类器 CascadeClass ...

  8. hadoop官网介绍及如何下载hadoop(2.4)各个版本与查看hadoop API介绍

    1.如何访问hadoop官网?2.如何下载hadoop各个版本?3.如何查看hadoop API? 很多同学开发都没有二手资料,原因很简单觉得不会英语,但是其实作为软件行业,多多少少大家会英语的,但是 ...

  9. shell script中的$*和$@

    在shell script中,$*和$@都是获取所有的命令行参数,但是这两者在使用的过程中会有细微的差别,差别主要是在有没有使用双引号,即是直接使用$*,$@,还是使用"$*",& ...

  10. 在JS中调用JAVA变量

    在JS中调用JAVA变量可以,方法是:var JS变量名 = “<%=JAVA变量名 %>”<%中间写java代码,跟在JSP中一样%>在JAVA中 ,无法调用JS变量