您好,登錄后才能下訂單哦!
本篇內容主要講解“C++動態規劃中關于背包問題怎么解決”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“C++動態規劃中關于背包問題怎么解決”吧!
背包問題,難點往往在第一步:dp數組表示什么
分割等和子集問題,較好的方式是:求裝滿背包后最大重量是多少(有點繞哈哈)
這是個題型:對于判斷能不能恰好裝滿背包的問題,用dp表示重量,判斷是否最終的dp[m]==m
bool canPartition(int* nums, int numsSize){ //首先數組元素求和的sum,若sum%2==1,返回false //若sum%2==0,定義m=sum/2,n=numsSize //則問題變成了能否裝滿容量為m的背包 //進一步變成了求裝滿容量為m的背包得到的最大價值量(本題價值量即為重量) //1.dp[j]表示裝滿容量為j的背包能獲得的最大價值量 //2.遞推式:dp[j]=fmax(dp[j],dp[j-nums[i]]+nums[i]); //3.dp數組初始化:dp[i]=0; //4.遍歷順序:0-1背包順序(滾動數組) int sum=0; for(int i=0;i<numsSize;i++) sum+=nums[i]; if(sum%2==1) return false; int m=sum/2,n=numsSize; int dp[m+1]; for(int j=0;j<=m;j++) dp[j]=0; for(int i=0;i<n;i++){ for(int j=m;j>=nums[i];j--) dp[j]=fmax(dp[j],dp[j-nums[i]]+nums[i]); } if(dp[m]==m) return true; else return false; }
求組合數模板:dp[0]=1;dp[j]+=dp[j-nums[i]];
int findTargetSumWays(int* nums, int numsSize, int target){ //首先數組元素求和的sum,若滿足題意,m+(m-target)=sum //若(sum+target)%2==1,返回0; //若sum<abs(target),返回0; //否則,有m=(sum+target)/2; //問題就變成了整數m可以有多少表達式表示出 //進一步變成了求裝滿容量為m的背包的最大組合數 //1.dp[j]表示裝滿容量為j的背包的最大表達式的組合數 //2.遞推式: //組合問題模板:dp[0]=1;dp[j]+=dp[j-nums[i]]; //3.dp數組初始化:dp[i]=0;dp[0]=1; int sum=0; for(int i=0;i<numsSize;i++) sum+=nums[i]; if(sum<abs(target)||(sum+target)%2==1) return 0; int m=(sum+target)/2,n=numsSize; int dp[m+1]; for(int i=1;i<=m;i++) dp[i]=0; dp[0]=1; for(int i=0;i<n;i++){ for(int j=m;j>=nums[i];j--) dp[j]+=dp[j-nums[i]]; } return dp[m]; }
注意二維滾動數組不能寫在同一個for循環中,這題背一下
int findMaxForm(char ** strs, int strsSize, int m, int n){ //本題是二維背包,不過是比一維多了一步而已 //1.dp[i][j]表示背包容量為i個0、j個1時,最多能裝的物品個數 //2.遞推式: //dp[i][j]=fmax(dp[i][j],dp[i-cnt0][j-cnt1]+1); //3.dp數組初始化: //dp[i][j]=0; //4.遍歷順序:二維滾動數組(注意不能把i和j寫在同一個for循環中) int dp[m+1][n+1]; for(int i=0;i<=m;i++){ for(int j=0;j<=n;j++) dp[i][j]=0; } for(int k=0;k<strsSize;k++){ int cnt0=0,cnt1=0; int len=strlen(strs[k]); for(int i=0;i<len;i++){ if(strs[k][i]=='0') cnt0++; else cnt1++; } for(int i=m;i>=cnt0;i--){ for(int j=n;j>=cnt1;j--){ dp[i][j]=fmax(dp[i][j],dp[i-cnt0][j-cnt1]+1); } } } return dp[m][n]; }
多重背包和0-1背包唯一的區別在遍歷順序
我們知道01背包內嵌的循環是從大到小遍歷,為了保證每個物品僅被添加一次。
而完全背包的物品是可以添加多次的,所以要從小到大去遍歷
int change(int amount, int* coins, int coinsSize){ int m=amount,n=coinsSize; int dp[m+1]; for(int i=1;i<=m;i++) dp[i]=0; dp[0]=1; for(int i=0;i<n;i++){ for(int j=coins[i];j<=m;j++) dp[j]+=dp[j-coins[i]]; } return dp[m]; }
本題要求的是排列數(即考慮排列順序)
求排列數,外層遍歷重量,內層遍歷物品,且均為從左到右遍歷
int combinationSum4(int *nums,int n,int m){ //1.dp[j]表示背包容量為j時,有多少種方法能使背包被裝滿“ //2.遞推式: //dp[j]+=dp[j-nums[i]]; //3.初始化: //dp[i]=0;dp[0]=1; //4.遍歷順序: //本題要求的是排列數(即考慮排列順序) //求排列數,外層遍歷重量,內層遍歷物品,且均為從左到右遍歷 int dp[m+1]; for(int i=1;i<=m;i++) dp[i]=0; dp[0]=1; for(int j=0;j<=m;j++){ for(int i=0;i<n;i++){ if(j>=nums[i]&&dp[j]<INT_MAX-dp[j-nums[i]]) dp[j]+=dp[j-nums[i]]; } } return dp[m]; }
本題要求的是組合數(即不考慮排列順序)
求組合數,外層遍歷物品,內層遍歷重量,且均為從左到右遍歷
int int coinChange(int* coins, int coinsSize, int amount){ //1.dp[j]表示背包容量為j時,有多少種方法能使背包被裝滿“ //2.遞推式: //dp[j]+=dp[j-coins[i]]; //3.初始化: //dp[i]=0;dp[0]=1; //4.遍歷順序: //本題要求的是組合數(即不考慮排列順序) //求組合數,外層遍歷物品,內層遍歷重量,且均為從左到右遍歷 int m=amount,n=coinsSize; int dp[m+1]; for(int i=1;i<=m;i++) dp[i]=0; dp[0]=1; for(int i=0;i<n;i++){ for(int j=coins[i];j<=m;j++) dp[j]+=dp[j-coins[i]]; } return dp[m]; }
到此,相信大家對“C++動態規劃中關于背包問題怎么解決”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。