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. C# 二叉堆

    二叉堆数据结构讲解: http://www.cnblogs.com/yc_sunniwell/archive/2010/06/28/1766751.html   C#代码实现 using System ...

  2. pyqt最小化学习

    # -*- coding: cp936 -*- #!/usr/bin/env python # -*- coding:utf-8 -*- from PyQt4 import QtCore, QtGui ...

  3. MooseFS源代码分析(三)

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...

  4. Why Hadoop2

    自从Hadoop2出现之后,其迅速代替了Hadoop1的地位,并丰富了Hadoop的应用场景.假设如今有公司使用Hadoop的话,往往直接採用Hadoop2了. Hadoop2能被如此广泛的使用,肯定 ...

  5. 在OC和Swift中使用IBDesignable/IBInspectable

    iOS8新特性IBDesignable/IBInspectable,可以直接在XIB或者Storyboard中直接,设置UI类的属性.例 如:UIView.layer.borderWidth.bord ...

  6. windows 和linux 同步api对比

    初始化临界区 (win) InitializeCriticalSection(RTL_CRITICAL_SECTION &rtl_critial_section) (linux) pthrea ...

  7. gdal_merge.py

    1 gdal_merge.py: 合并(Merge)/镶嵌(Mosaic)工具.要求图像必须是相同坐标系统.具有相同的波段数:可以不同分辨率,可以有重叠区域(后加入图像覆盖先加入的图像). 注意:只能 ...

  8. PHP学习笔记三十四【记录日志】

    <?php function my_error2($errno,$errmes) { echo "错误号:".$errno; //默认时区是格林威治相差八个时区 //设置 1 ...

  9. iOS 开发者证书总结

    iOS 证书分两种类型. 第一种为$99美元的,这种账号有个人和公司的区别,公司账号能创建多个子账号,但个人的不能.这种账号可以用来上传app store 第二种为¥299美元的,这种账号只能用于企业 ...

  10. IOS 中关于自定义Cell 上的按钮 开关等点击事件的实现方法(代理)

    1.在自定义的Cell .h文件中写出代理,写出代理方法. @protocol selectButtonDelegate <NSObject> -(void)selectModelID:( ...