日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

dp问题 -挑战例题 2017-7-24

發(fā)布時(shí)間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dp问题 -挑战例题 2017-7-24 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

01 背包

題意:

  在N件物品取出若干件放在容量為W的背包里,每件物品的體積為W1,W2……Wn(Wi為整數(shù)),與之相對(duì)應(yīng)的價(jià)值為P1,P2……Pn(Pi為整數(shù))。求背包能夠容納的最大價(jià)值。

f[i][v] = max{ f[i-1][v] , f[i-1][ v-c[i] ] + w[i] }

?

#include <iostream> #include <cstdio> #include <cmath> using namespace std; const int maxn = 100 + 5;int n ,w; int v[maxn],s[maxn]; int dp[2][10010];int main() {cin>> n >> w;for(int i=1;i <= n;i++){cin >> v[i] >> s[i];}int now = 1,pre = 0;for(int i=1;i <= n;i++){for(int j=0;j<=w;j++){if(j < v[i])dp[now][j] = dp[pre][j];elsedp[now][j] = max(dp[pre][j] , dp[pre][j-v[i]]+s[i]); // 不選 就是dp[i-1][j]//選就是dp[i-1][j-v[i]]+s[i] }swap (now,pre);}cout<< dp[pre][w]<<endl;return 0; } 01 背包

?下面是優(yōu)化過(guò)內(nèi)存的

#include <iostream> #include <cstdio> #include <cmath> #include <string.h> using namespace std; const int maxn = 100 + 5;int n ,w; int v[maxn],s[maxn]; int dp[10010];int main() {cin>> n >> w;for(int i=1;i <= n;i++){cin >> v[i] >> s[i];}memset(dp,0,sizeof(dp));for(int i=1;i <= n;i++){for(int j=w;j >= v[i];j--)//從上面一個(gè)狀態(tài)轉(zhuǎn)移 但是倒著寫 上面一個(gè)狀態(tài)就不會(huì)轉(zhuǎn)移了dp[j] = max(dp[j] , dp[j-v[i]]+s[i]);}cout<< dp[w]<<endl;return 0; } 01 背包優(yōu)化

?

完全背包

題意:

  在N種 物品取出若干件放在容量為W的背包里,每件物品的體積為W1,W2……Wn(Wi為整數(shù)),與之相對(duì)應(yīng)的價(jià)值為P1,P2……Pn(Pi為整數(shù))。求背包能夠容納的最大價(jià)值。

思路:

  完全背包和01 背包的區(qū)別就是 能夠存儲(chǔ)的物品可以挑選多次

所以 轉(zhuǎn)移方程也就變成了?dp[i][j] = max(dp[i-1][j] , dp[i][j-v[i]]+s[i]); // 不選 就是dp[i-1][j] ?選就用dp[i][j-v[i]]+s[i]

//而01背包 就是dp[i][j] = max(dp[i-1][j] , dp[i-1][j-v[i]]+s[i])

?

f[i][v] = max{ f[i-1][v-k*c[i]] + k*w[i] | 0 <= k*c[i] <= v}

#include <iostream> #include <cstdio> #include <cmath> using namespace std; const int maxn = 100 + 5;int n ,w; int v[maxn],s[maxn]; int dp[2][10010];int main() {cin>> n >> w;for(int i=1;i <= n;i++){cin >> v[i] >> s[i];}int now = 1,pre = 0;for(int i=1;i <= n;i++){for(int j=0;j<=w;j++){if(j < v[i])dp[now][j] = dp[pre][j];elsedp[now][j] = max(dp[pre][j] , dp[now][j-v[i]]+s[i]); // 不選 就是dp[i-1][j]//選就是dp[i][j-v[i]]+s[i] }swap (now,pre);}cout<< dp[pre][w]<<endl;return 0; } 完全背包

下面也是優(yōu)化過(guò)的

#include <iostream> #include <cstdio> #include <cmath> #include <string.h> using namespace std; const int maxn = 100 + 5;int n ,w; int v[maxn],s[maxn]; int dp[10010];int main() {cin>> n >> w;for(int i=1;i <= n;i++){cin >> v[i] >> s[i];}memset(dp,0,sizeof(dp));for(int i=1;i <= n;i++){for(int j=v[i];j <= w;j++)//可以從上面一個(gè)狀態(tài)轉(zhuǎn)移 正著寫 就能覆蓋上次的計(jì)算了dp[j] = max(dp[j] , dp[j-v[i]]+s[i]);}cout<< dp[w]<<endl;return 0; } 完全背包 優(yōu)化

?

多重部分和問題 ?//多重背包

題意 :

  有n中不同大小的數(shù)字ai,每種各mi個(gè)。判斷是否可以從這些數(shù)字之中選出若干使他們的大小恰好為K.

樣例 : n = 3 ?a={3, 5, 8} ?m={3, 2, 2} K= 17

? ? ? ? 17 = 3*3 + 8?

思路:

  dp[i+1][j] //用前i種數(shù)加和得到j(luò)時(shí) 第i種數(shù)最多剩余多少個(gè)

  

        ? ?m[i] ?, dp[i][j] >= 0 //說(shuō)明前i個(gè)數(shù)已經(jīng)可以等于j 了 不需要 第 i+1 個(gè)數(shù)

  dp[i+1][ j ] = -1 , j < a[i] || dp[i+1][ j-a[i] ] <= 0,//?j < a[i] 目前還不是很懂這個(gè)條件?...dp[i+1][ j-a[i] ] <= 0 說(shuō)明此時(shí)候沒法再用a[i]了

         dp[i+1][ j-a[i] ] -1,//和完全背包差不多, 如果此時(shí)a[i] 還存在 那么 就從 dp[i+1][ j-a[i] ] 去除1個(gè)a[i] 就可以得到..           ?

#include <iostream> #include <cstdio> #include <string.h> using namespace std; const int mod = 1e9 + 7; const int maxn = 100000 + 5; const int INF = 0x3f3f3f3f; typedef long long LL;int n,k; int a[maxn] , m[maxn]; int dp[maxn];void solve() {memset(dp,-1,sizeof(dp));dp[0] = 0; //加和得到0 需要0個(gè)數(shù)字for(int i=0;i < n;i++){for(int j=0;j <= k;j++){if(dp[j] >= 0) dp[j] = m[i];else if(dp[ j-a[i] ] <= 0 || j < a[i] ){dp[j] = -1;}else{dp[j] = dp[ j-a[i] ] -1;}}}if(dp[k] >= 0) printf("Yes\n");else printf("No\n"); }int main() {cin >> n >> k;for(int i =0;i < n;i++){cin >> a[i] >> m[i];}solve ();return 0; } 多重部分和

?

// http://www.hankcs.com/program/cpp/poj-1742-coins.html

?

最長(zhǎng)上升子序列 (LIS)

思路:做過(guò)好多次了 ?就是dp[i] 記錄的長(zhǎng)度為 i + 1 的時(shí)候中末尾元素的最小值

//具體插入過(guò)程 看挑戰(zhàn) P 66

#include <iostream> #include <cstdio>using namespace std; const int mod = 1e9 + 7; const int maxn = 10000 + 5; const int INF = 0x3f3f3f3f; typedef long long LL; int n; int s[maxn]; int dp[maxn]; void solve () {fill(dp,dp+n,INF);for(int i=0;i < n;i++){*lower_bound(dp,dp+n,s[i]) = s[i];//for(int j= 0;j < n;j++)// cout<< dp[j] <<" ";// cout<<endl; }printf("%d\n",lower_bound(dp,dp+n,INF) - dp); } int main() {cin >> n;for(int i=0;i < n;i++)cin >> s[i];solve ();return 0; } LIS

?

轉(zhuǎn)載于:https://www.cnblogs.com/Draymonder/p/7227276.html

總結(jié)

以上是生活随笔為你收集整理的dp问题 -挑战例题 2017-7-24的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。