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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

dp入门 专题记录 2017-7-26

發布時間:2024/10/12 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dp入门 专题记录 2017-7-26 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

POJ3176-Cow Bowling

題目大意:現有n行數,以金字塔的形式排列,即第一行一個數字,第二行2個數字,依次類推,現在需要找一條從第一層到第n層的路線,使得該路線上的所有點的權值和最大

思路:根據分析可以得出狀態轉移方程:dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]),dp[i][j]表示以第i行第j個位置作為終點的的線路中的最大權值。

#include <iostream> using namespace std; const int N = 360; int s[N][N]; int dp[N][N]; int main () {int n;cin >> n;for(int i=1;i <= n;i++)for(int j=1;j <= i;j++)cin >> s[i][j];for(int i=n;i ;i--){for(int j=1;j <= i;j++)//從下網上依次找到最大的 {dp[i][j] = s[i][j] + max(dp[i+1][j],dp[i+1][j+1]);}}cout<< dp[1][1]<<endl;return 0; } A

?

Poj 2229(dp)

題目大意:求把一個整數分解為2的冪的和共有幾種方案

6=1+1+1+1+1+1

6=1+1+1+1+2

6=1+1+2+2

6=1+1+4

6=2+2+2

6=2+4

思路1:

如果i為奇數,肯定有一個1,把f[i-1]的每一種情況加一個1就得到fi,所以f[i]=f[i-1]

如果i為偶數,如果有1,至少有兩個,則f[i-2]的每一種情況加兩個1,就得到i,

      如果沒有1,則把分解式中的每一項除2,則得到f[i/2] ?(比如 4 = 2+2 ,4 = 4 ?除2后就變成 2 = 1 + 1 , 2 = 2) ?

所以f[i]=f[i-2]+f[i/2]

#include <iostream> #include <cstdio>using namespace std; const int mod = 1e9 ; const int maxn = 1000000 + 5; typedef long long LL;LL dp[maxn];int main() {int n;cin >> n;dp[0] = 1,dp[1] = 1;for(int i=2;i<=n;i++){if(i & 1)//奇數dp[i] = dp[i-1];else//偶數 {dp[i] = dp[i-2] + dp[i/2],dp[i] %= mod;}}cout<< dp[n] <<endl;return 0; } B_遞推

?思路2:

題目分析: d[i][v] ?表示前i物品之和為v的最多數量, ?有狀態轉移方程 d[i][v] ?= sum( d[i-1][v-k*c[i]] | ? 0 < k*c[i] <=v)

? ? ? ? ? ? ? ? ? ? ? 利用完全背包O(vn)優化的思想, 這里思想是相同的,則d[v] += d[v-c[i]]?

#include <iostream> #include <cstdio>using namespace std; const int mod = 1e9; const int maxn = 1e6 + 5; const int INF = 0x3f3f3f3f; typedef long long LL; int s[20]; LL dp[maxn];int main() {int n;scanf("%d",&n);s[0] = 1;for(int i=1;i<20;i++)s[i] = s[i-1]*2; //打表記錄 2的0-20次方dp[0] = 1;for (int i =0;i < 20; i++){if(s[i] > n) break;for(int j=s[i];j <= n ;j++){dp[j] += dp[ j-s[i] ] ;if(dp[j] > mod )dp[j] %= mod;}}printf("%lld",dp[n]);return 0; } B_完全背包 容易T

?

poj 2385?Apple Catching

題意:有兩棵蘋果樹,標號分別為1,2。每分鐘有其中的一棵樹會掉下一個蘋果,奶牛一分鐘只能在其中一棵樹下接到蘋果,但她不知道下一分鐘會是那棵樹掉下蘋果,所以她就要在兩棵樹下來回跑。但她只會在樹下跑W次。問你在T分鐘內,奶牛bessie最多能接到多少蘋果。

?

思路:一道簡單的DP。

先給出狀態轉移方程:dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+count。這里的dp[i][j]代表在第i分鐘移動j次最多能接到的蘋果數。

在第i分鐘奶牛到某棵樹下有兩種狀態:

1.從另一棵樹走過來(dp[i-1][j-1])

2.本來就呆在這棵樹下(dp[i-1][j])。所以在第i分鐘時能接到的最大蘋果數就是dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+count。

這里count的值可以這樣計算:如果j為偶數說明她移動了j次又回到了第一棵樹下,則count=a[i]==1?1:0;即count=2-a[i]。若j為奇數說明她移動了j次后到了第二棵樹下,則count=a[i]==2?1:0(即count=a[i]-1)。

?

#include <iostream> #include <cstdio>using namespace std; const int mod = 1e9 + 7; const int maxn = 1000 + 5; const int INF = 0x3f3f3f3f; typedef long long LL; int s[maxn]; int dp[maxn][40];//p[i][j]代表第i棵樹 最多j次走 最大能吃到的Apple int solve (int t,int w) {int count;for(int i=0;i <= w;i++) dp[0][i] = 0;//初始化for(int i =1;i <= t;i++)//一共最多w次 {dp[i][0] = dp[i-1][0] + 2-s[i]; //如果一次沒動過 只要s[i] = 1 就 +1for(int j=0;j <= w;j++){if(j % 2) //j是奇數 此時在第2顆樹上count =s[i] -1 ; //如果s[i] =2 說明有1次else //j是偶數 此時在第1顆樹上count = 2-s[i];dp[i][j] = max(dp[i-1][j-1],dp[i-1][j]) + count;}}count = 0;for(int i=1;i <= t;i++){for(int j=0;j <= w ;j++){if(dp[i][j] > count )count = dp[i][j];}}return count; }int main() {int t,w;scanf("%d %d",&t,&w);for(int i=1;i <= t;i++){cin >> s[i];}cout<< solve(t,w)<<endl;return 0; } C

?

//其實第三題的 count不需要比較 因 //為遞推的時候dp = max(dp[i-1][j] ,dp[i][j]) 了 就是現在的狀態記錄的已經是最優解 count = 0;for(int i=1;i <= t;i++){for(int j=0;j <= w ;j++){if(dp[i][j] > count )count = dp[i][j];}}return count; //所以這段可以 直接修改為 return dp[t][w]; c題補充

??

POJ3616Milking Time

?

題意:

在一個農場里,在長度為N個時間可以擠奶,但只能擠M次,且每擠一次就要休息t分鐘;

接下來給m組數據表示擠奶的時間與奶量求最大擠奶量

思路:

每次 結束時間 += 休息的時間,接著按照 開始時間 排序

接著 狀態轉移方程 dp[i] = max(dp[i] , dp[j] + dp[i].cost) ( j > i && s[j].start >= s[i].end )

#include <iostream> #include <algorithm> using namespace std; struct P{int left,ri,cost;bool operator < (const P & other)const{return (left < other.left||(left == other.left) &&ri < other.ri );} }s[1010];int dp[1010];int main () {int n,m,t;cin >>n>>m>>t;for(int i=1;i<= m;i++){cin >> s[i].left>> s[i].ri >> s[i].cost;s[i].ri += t;}sort(s+1,s+1+m);for(int i=m; i ;i--){dp[i] = s[i].cost;for(int j=i+1 ; j <= m;j++){if(s[j].left >= s[i].ri)dp[i] = max(dp[i], dp[j] + s[i].cost);//狀態轉移方程 }}int count = 0;for(int i=1;i <= m;i++)count = max(count ,dp[i]);cout<< count<<endl;return 0; } D

??

poj(3280)Cheapest Palindrome(區間dp)

題意:

  給出一個由m中字母組成的長度為n的串,給出m種字母添加和刪除花費的代價,求讓給出的串變成回文串的代價。?

思路:

  我們知道求添加最少的字母讓其回文是經典dp問題,轉化成LCS求解。這個是一個很明顯的區間dp

  我們定義dp [ i ] [ j ] 為區間 i 到 j 變成回文的最小代價。

那么對于dp [ i ] [ j ]有三種情況

首先:對于一個串如果s[ i ]==s[ j ],那么dp [ i ] [ j ]=dp [ i+1 ] [ j-1 ]

其次:如果區間 [ i+1, j ]已經維護成回文串,那么dp [ i ] [ j ]=dp [ i+1 ] [ j ]+min(add[ i ],del[ i ]);

最后,如果區間?[ i, j-1 ]已經維護成回文串,那么dp [ i ] [ j ]=dp [ i ] [ j-1 ]+min(add[ j ],del[ j ]);

#include <stdio.h> #include <string.h> #include <cmath> #include <iostream> using namespace std;int dp[2005][2005]; int cost[300]; int n,m; char s[2005];int main () {while (cin >> m >> n)//m表示可以增刪的字符的個數 n表示字符串長度 {memset(dp,0,sizeof(dp));cin >> s+1 ;for(int i=0;i < m;i++){char ch; int x ,y;cin >> ch >>x >> y;cost[ ch ] = min(x,y);}//存儲數據for(int i=n; i ;i--){for(int j=i+1;j <= n;j++){if( s[i] == s[j] )dp[i][j] = dp[i+1][j-1];//長度收縮一下elsedp[i][j] = min(dp[i+1][j] + cost[ s[i] ],dp[i][j-1] + cost[ s[j] ]);}}cout<< dp[1][n] <<endl;}return 0; } E

?

POJ 1742 Coins

題意:

  給出n個coins 的價值 和 數量 求出 可以構造出 小于m的數量

思路:

  基本就是挑戰的原題了 ? 用的多重部分和 看到網上說的就是多重背包

  加深了一點點兒的想法把

dp[i][j] := 用前i種硬幣湊成j時第i種硬幣最多能剩余多少個(-1表示配不出來)如果dp[i - 1][j] >= 0(前i-1個數可以湊出j,那么第i個數根本用不著)直接為C[i] dp[i][j] = 如果j < A[i]或者dp[i][j - a[i]] <=0 (面額太大或者在配更小的數的時候就用光了)-1其他(將第i個數用掉一個) dp[i][j-a[i]] - 1

?

#include <iostream> #include <string.h> #include <algorithm> using namespace std; const int maxn = 100010;int price[105] , num[105]; int dp[maxn]; //dp[i][j]表示在用前i種coins 用的第i種硬幣還剩余的情況 int n,m;int main () {while (cin >> n >> m && n+m){for(int i=1;i <= n;i++ )cin >> price[i];for(int i=1;i <= n;i++)cin >>num[i];memset(dp,-1,sizeof(dp));dp[0] = 0;for(int i=1;i <= n;i++){for(int j=0;j <= m;j++){if(dp[ j ] >= 0)//前面 i-1已經算出來了dp[j] = num[i];else if(dp[ j-price[i] ] <= 0 || j < price[i] )dp[j] = -1;elsedp[j] = dp[j-price[i] ] -1;}}int ans = 0;for(int i=1;i <= m;i++)if( dp[i] >= 0 )ans++;cout<< ans <<endl;}return 0; } F http://www.hankcs.com/program/cpp/poj-1742-coins.html 參考網址

?

?背包加深一下理解 ?就是 如果dp優化成一維的 ?如果需要更新自己當前行的值 就 j從0到m ?如果不需要更新自己當前行的值 ?j就從m到0

?

轉載于:https://www.cnblogs.com/Draymonder/p/7220738.html

總結

以上是生活随笔為你收集整理的dp入门 专题记录 2017-7-26的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。