P3092 [USACO13NOV]No Change G 状压dp

该代码实现了一个动态规划算法,通过状态i表示使用特定组合的硬币能购买的最大物品数。遍历所有硬币组合,寻找能增加物品数量的状态转移。如果找到能购买全部物品的组合,记录其硬币总价值。最后输出最大硬币价值或-1表示无法购买所有物品。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路:dp[i] 表示使用状态i的硬币能买到的最多物品数,然后寻找比i状态多用一个硬币的 下一个状态 也就是状态 i&(1<<j)  进行转移。 

#include <bits/stdc++.h>
typedef long long ll;

using namespace std;
#define pb push_back
#define inf 0x3f3f3f3f
#define endl "\n"
#define d(a) cout<<#a<<a<<endl;
#define max(a, b) a > b ? a : b
const ll maxn=(1<<16)+20;
int k,n;
ll coin[20];

int  s[100010];
int dp[maxn];

int find1(int l,int r,int p){
	int now=s[l];
	int res=1;
	while (l<=r){
		int mid=(l+r)>>1;
		if (s[mid]-now<=p) res=mid,l=mid+1;
		else r=mid-1;
		
	}
	
	return res;
	
}




int main(){
	bool vis=false;
	ll ans=0;
	cin>>k>>n;
	memset(dp,0,sizeof(dp));
	memset(s,0,sizeof(s));
	for (int i=1;i<=k;i++) {
		cin>>coin[i];

	}
	for (int i=1;i<=n;i++) {
		int mid;
		cin>>mid;
		s[i]=s[i-1]+mid;
	}
	for (int i=0;i<(1<<k);i++){
		for (int j=0;j<k;j++){
			if (i&(1<<j)) continue;
			int mid;
			mid=find1(dp[i],n,coin[j+1]);
			dp[(i|(1<<j))]=max(dp[(i|(1<<j))],mid);  //假设i状态用了x个硬币
//这个步骤就是寻找合法的使用x+1个硬币的状态,进行转移,硬币由少到多,是合法的,正确的。
		}
		if (dp[i]==n){
			vis=true;
			ll mid=0;
			for (int j=0;j<k;j++){
				if (i&(1<<j)) continue;
				mid+=coin[j+1];
			}
			ans=max(ans,mid);
			
		}
		
	}
	if (!vis) cout<<-1<<endl;
	else cout<<ans<<endl;
	
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值