【dp】砝码称重模型(选或不选)

目录

蓝桥杯 砝码称重

牛客 我不是大富翁 

 abc 344 D

cf div3 933 D 

牛客 旗鼓相当的对手


蓝桥杯 砝码称重

题目链接: https://www.lanqiao.cn/problems/1447/learning/?page=1&first_category_id=1&sort=students_count&category_id=3&name=%E7%A0%9D%E7%A0%81%E7%A7%B0%E9%87%8D 

思想:

不选  = j

放右边 = j + a[i]

放左边 = abs (j - a[i])

代码:

#include<bits/stdc++.h>
using namespace std;

#define int long long

const int N = 2e5+5;

int n,a[N];
int dp[105][N];

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	dp[0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=1e5;j++){
			if(dp[i-1][j]){
				dp[i][j]=1;  //不选
				dp[i][j+a[i]]=1;  //放右边
				dp[i][abs(j-a[i])]=1;  //放左边
			}
		}
		
	}
	int ans=0;
	for(int i=1;i<=1e5;i++){
		if(dp[n][i]) ans++;
	}
	cout<<ans<<"\n";
	
	
	
	return 0;	

}

牛客 我不是大富翁 

题目链接 :https://ac.nowcoder.com/acm/contest/75771/D

思想:开二维bool 数组,判断第 i 次操作 是否可能位于 j 的位置

代码:

#include<bits/stdc++.h>
using namespace std;

#define int long long

const int N = 5001;

int n,m;
int a[N];
bool dp[N][N]; //i次操作是否可能位于j的位置

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>a[i];
		a[i]%=n;
	}
	
	dp[0][0]=1;
	for(int i=1;i<=m;i++){
		for(int j=0;j<n;j++){
			if(dp[i-1][(n+j-a[i])%n]||dp[i-1][(j+a[i])%n]){
				dp[i][j]=1;
			}
			else dp[i][j]=0;
		}
	}
	if(dp[m][0]) cout<<"YES\n";
	else cout<<"NO\n";
	
	
	return 0;	

}

 abc 344 D

题目链接:https://atcoder.jp/contests/abc344/tasks/abc344_d

思想:一维数组表示当前长度的最小次数

?为什么要开dp2

代码:

#include<bits/stdc++.h>
using namespace std;

#define int long long

const int N = 1010;

string s,t;
int n,m;
int f[N][N];  //表示在前i项中 此时长度为j 的最小次数

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	cin>>s;
	vector<int> dp(s.size()+1,1e15);
	dp[0]=0;
	
	cin>>n;
	for(int i=1;i<=n;i++){
		vector<int> dp2=dp;
		cin>>m;
		while(m--){
			cin>>t;
			for(int j=0;j<s.size();j++){
				if(j+t.size()<=s.size()&&s.substr(j,t.size())==t){
					dp2[j+(int)t.size()]=min(dp2[j+(int)t.size()],dp[j]+1);
				}
			}
		}
		dp=dp2;
	}
	if(dp.back()==1e15){
		cout<<"-1\n";
	}
	else cout<<dp.back()<<"\n";
	
	
	
	return 0;	

}


cf div3 933 D 

牛客 旗鼓相当的对手

题目链接:  https://ac.nowcoder.com/acm/problem/269823

代码:

// Problem: 旗鼓相当的对手
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/76681/G
// Memory Limit: 131072 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;

#define int long long

const int N = 2e5+5;

int n,a[N];
int dp[N];

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	cin>>n;
	
	int sum=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];	
		sum+=a[i];
	}	
	
	//dp[i]表示体积为sum/2 n个能装的最大体积
	for(int i=1;i<=n;i++){
		for(int j=sum/2;j>=a[i];j--){
			//不选和选
			dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
		}
	}
	
	//另一个背包是sum-dp[sum/2] 
	cout<<(sum-dp[sum/2])-dp[sum/2]<<"\n";
	
	
	
	return 0;	

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值