算法训练营day43_动态规划(3.15)
1049.最后一块石头的重量II
这道题没想出来。
关键在于,可以转化:分成两部分,求最小差值(两个碰撞,一直碰,转化成两堆只碰一次);
并且,尽量让两部分相等,也就是说一部分和尽量为sum/2;这就可以用背包了,求从前n-1个里挑,重量不超过sum/2的最大值(最大值不会超过sum/2);
dfs
只过了80/90
搜完最后一个位置,更新答案;
当前位置有两个选择,要么一阵,要么二阵;
class Solution {
public:
int ans;
void dfs(int u,int l,int r,vector<int> &stones){
if(u==stones.size()){
ans=min(ans,abs(l-r));
return;
}
dfs(u+1,l+stones[u],r,stones);
dfs(u+1,l,r+stones[u],stones);
}
int lastStoneWeightII(vector<int>& stones) {
ans=110;
int n=stones.size();
dfs(0,0,0,stones);
return ans;
}
};
动态规划
一维
class Solution {
public:
int f[3001];
int lastStoneWeightII(vector<int>& stones) {
int n=stones.size();
int sum=0;
for(int i=0;i<n;i++) sum+=stones[i];
memset(f,0,sizeof f);
for(int i=0;i<n;i++){
for(int j=sum/2;j>=stones[i];j--){
f[j]=max(f[j],f[j-stones[i]]+stones[i]);
}
}
return sum-f[sum/2]-f[sum/2];
}
};
二维
需要初始化0号物品涉及到的;
class Solution {
public:
int f[40][3001];
int lastStoneWeightII(vector<int>& stones) {
int n=stones.size();
int sum=0;
for(int i=0;i<n;i++) sum+=stones[i];
memset(f,0,sizeof f);
for(int j=stones[0];j<=sum/2;j++){
f[0][j]=stones[0];
}
for(int i=1;i<n;i++){
for(int j=0;j<sum;j++){
f[i][j]=f[i-1][j];
if(j>=stones[i])f[i][j]=max(f[i][j],f[i-1][j-stones[i]]+stones[i]);
}
}
return sum-f[n-1][sum/2]-f[n-1][sum/2];
}
};
494.目标和
从数组里选数,一部分加,一部分减,加+减=sum,加-减=target,可得出加的这部分和为(sum+target)/2;
因此如果sum+target是奇数,不可以;如果sum比abs(target)小,不可以;
转化成了:从数组里选数,和为(sum+target)/2的方案;用01背包;
- 状态:f(i,j)从前i个选,重量为j的方案;
- 转移:f(i,j)=f(i-1,j-v[i])+f(i-1,j);
- 初始化:f(0)=1;
- 外层i正向,内层j反向(01模板);
class Solution {
public:
int f[20001];
int findTargetSumWays(vector<int>& nums, int target) {
int n=nums.size();
memset(f,0,sizeof f);
int sum=0;
for(int i=0;i<n;i++) sum+=nums[i];
if(abs(target)>sum) return 0;
if((sum+target)&1) return 0;
f[0]=1;
for(int i=0;i<n;i++){
for(int j=(sum+target);j>=nums[i];j--){
f[j]+=f[j-nums[i]];
}
}
return f[(sum+target)/2];
}
};
474.一和零
背包套路,多了个维度;
class Solution {
public:
int f[110][110];
int a[610],b[610];
int findMaxForm(vector<string>& strs, int m, int n) {
memset(f,0,sizeof f);
int len=strs.size();
for(int i=0;i<len;i++){
for(int j=0;j<strs[i].size();j++){
if(strs[i][j]=='0') a[i]++;
else b[i]++;
}
}
for(int i=0;i<len;i++){
for(int j=m;j>=a[i];j--){
for(int k=n;k>=b[i];k--){
f[j][k]=max(f[j][k],f[j-a[i]][k-b[i]]+1);
}
}
}
return f[m][n];
}
};