
要转化为0和1背包,其实是可以转化为分割等和子集。可以分成两堆,如果是两堆相等的抵消就为0,否则用大堆的和-小堆的和。但是我觉得可能其中一堆尽量装满半个总体重量,分成两堆不能完全确保互相消掉就是最优结果,可能还有堆内相消情况。看了题解后发现其实不会出现堆内相消,而且尽量装满总重量一半,代表另外一堆和本堆数值最接近,差值最小。(感觉有点绕,不是很清楚)
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int sum=0;
for(int i=0;i<stones.size();i++){
sum+=stones[i];
}
int target=sum/2;
vector<int> dp(15001,0);
for(int i=0;i<stones.size();i++){
for(int j=target;j>=stones[i];j--){
dp[j]=max(dp[j],dp[j-stones[i]]+stones[i]);
}
}
return sum-dp[target]-dp[target];
}
};

看了题解。 假设一堆left为x,总量计算为sum,那么另一堆right为sum-x。那么left-right=target。即x-(sum-x)=target,x=(target+sum)/2.转为dp[x]有多少种方法可以装满。
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum=0;
for(int i=0;i<nums.size();i++){
sum+=nums[i];
}
if(abs(target)>sum) return 0;
sum+=target;
if(sum%2==1) return 0;
int rong=sum/2;
vector<int> dp(rong+1,0);
dp[0]=1;
for(int i=0;i<nums.size();i++){
for(int j=rong;j>=nums[i];j--){
dp[j]+=dp[j-nums[i]];
}
}
return dp[rong];
}
};

这个一遍过,没看题解。数组里对于dp[x][y]代表x个0,y个1的最大长度,当前元素是选或不选,不选的话就是上一次的状态,选的话就是dp[x-当前元素0个数][y-当前元素1个数]+1
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>> dp(m+1,vector<int>(n+1,0));
for(int i=0;i<strs.size();i++){
int tmp0=0;
int tmp1=0;
for(int j=0;j<strs[i].size();j++){
if(strs[i][j]=='1')
tmp1+=1;
else tmp0+=1;
}
for(int j=m;j>=tmp0;j--){
for(int k=n;k>=tmp1;k--){
dp[j][k]=max(dp[j][k],dp[j-tmp0][k-tmp1]+1);
}
}
}
return dp[m][n];
}
};
文章讲述了如何将0-1背包问题转化为子集问题,利用动态规划解决,重点在于理解如何构造dp数组以及在处理字符串组合问题时的应用,强调了堆内相消的可能性和尽量使一堆重量接近总量一半以减小差值的思想。
1204

被折叠的 条评论
为什么被折叠?



