DP(状压专题九)

20 篇文章 0 订阅

题意 : 有 k ≤ 16 k \leq16 k16枚硬币,每枚价值 a [ i ] ≤ 1 e 8 a[i] \leq 1e8 a[i]1e8,有 m ≤ 1 e 6 m\leq1e6 m1e6件物品, 每件物品 c o s t [ i ] ≤ 1 e 4 cost[i]\leq1e4 cost[i]1e4, 而且必须顺序买, 问在不找零的情况下自己最多能剩多少钱

>> face <<

Strategy:状压DP, i是一个表示二进制的十进制数,'1’是当前位置的硬币被选了

状态: dp[i]->状态为i所能顺序买最远物品的下标

目标: 所有dp[i] = m 的i里对应的0位(没有选的硬币),的价值的最大值

边界: dp[0] = 0;

合法判断: 无

转移方程:

d p [ i ∣ 1 &lt; &lt; j − 1 ] = m a x ( d p [ i ∣ 1 &lt; &lt; j − 1 ] , u p p e r b o u n d ( s u m , s u m + m , s u m [ d p [ i ] ] + a [ j ] ) − s u m ) dp[i | 1 &lt;&lt; j - 1] = max(dp[i | 1 &lt;&lt; j - 1], upperbound(sum, sum + m, sum[dp[i]] + a[j]) - sum) dp[i1<<j1]=max(dp[i1<<j1],upperbound(sum,sum+m,sum[dp[i]]+a[j])sum)

attention: 转移方程一定要缜密

双倍经验: 注意转移方程

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define oo 0x3f3f3f3f
#define ll long long
#define db double
#define all(a) a.begin(), a.end()
#define met(a, b) memset(a, b, sizeof(a))
#define what_is(x) cout << #x << " is " << x << endl
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (int i = (a); i >= (b); --i)
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define lowbit(x) x &(-x)
#define bin(x) cout << #x << " is " << bitset<sizeof(int) * 2>(x) << endl
#define pi acos(-1.0)
using namespace std;
using namespace __gnu_pbds;
const int maxn = 1e5 + 10;
const int mod = 1e9 + 7;
ll sum[maxn], a[17];
ll n, m, money[maxn];
int dp[1 << 16];
const db eps = 1e-8;

int main()
{
	ios::sync_with_stdio(0);
	cin >> n >> m;
	_rep(i, 1, n){
		cin >> a[i];
	}
	_rep(i, 1, m){
		ll x;
		cin >> x;
		sum[i] = sum[i - 1] + x;
	}

	_rep(i, 0, (1 << n) - 1){
		_rep(j, 1, n){
			if(i >> j - 1 & 1)
				continue;
			
			dp[ i | 1 << j - 1] = max(dp[i | 1 << j - 1], (int)(upper_bound(sum + 1, sum + 1 + m, sum[dp[i]] + a[j]) - sum - 1));
		}
	}	
	
	
	ll ans = -1;
	_rep(i, 0, (1 << n) - 1){
		if(dp[i] == m){
			ll left = 0;
			_rep(j, 1, n){
				if(!(i >> j - 1 & 1)){
					left += a[j];
				}
			}
			ans = max(ans, left);
		}
	}
	cout << ans << endl;
}


第一次回顾, 重点:转移方程的转移

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (int i = (a); i >= (b); --i)
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rof(i, a, b) for (int i = (a); i > (b); --i)
#define ll long long
#define db double
#define oo 0x3f3f3f3f
#define eps 0.00001
#define all(x) x.begin(), x.end()
#define met(a, b) memset(a, b, sizeof(a))
#define what_is(x) cerr << #x << " is " << x << endl
#define lowbit(x) x &(-x)
using namespace std;
const int maxn = 1e5 + 10;
const int mod = 9999973;
int dp[1 << 16], a[22], sum[maxn], n, m;
int main()
{
	ios::sync_with_stdio(0);
	cin >> n >> m;
	_rep(i, 1, n)
	{
		cin >> a[i];
	}
	_rep(i, 1, m)
	{
		int xx;
		cin >> xx;
		sum[i] = sum[i - 1] + xx;
	}
	
	_rep(i, 0, (1<< n) - 1){
		_rep(j,1, n){
			if(!(i >> j - 1 & 1)){
				dp[i | 1 << j - 1] = max(dp[i | 1 << j - 1], (int)(upper_bound(sum + 1, sum + 1 + m, sum[dp[i]] + a[j]) - sum - 1));
			}
		}
	}
	ll ans = -1;
	_rep(i, 0, (1<< n)-1){
		if(dp[i] == m){
			ll tmp = 0;
			_rep(j, 1, n){
				if(!(i >> j - 1 & 1)){
					tmp += a[j];
				}
			}
			ans = max(ans , tmp);
		}
	}
	cout << ans << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值