1. 程式人生 > >基礎簡單DP

基礎簡單DP

hide namespace 遞推 div blog 分割 display ont 簡單

狀態比較容易表示,轉移方程比較好想,問題比較基本常見 遞推、背包、LIS(最長遞增序列),LCS(最長公共子序列)

HDU 2048 數塔

由上往下推 狀態數太多(100!) 可以由下往上推:

dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+dp[i][j])

儲存的話就直接一個二維數組a[110][110]

HDU2018 母牛

有一頭母牛,它每年年初生一頭小母牛。每頭小母牛從第四個年頭開始,每年年初也生一頭小母牛。請編程實現在第n年的時候,共有多少頭母牛?

斐波那契數列 遞推 線性遞歸

dp[i]=dp[i-1]+dp[i-3];

HDU2044 一只小蜜蜂

斐波那契數列 遞推 線性遞歸

先發現 n(n>=3)可由n-1及n-2到達 所以遞推得到到達n的方法是到達n-1的方法+到達n-2的方法

HDU2050 折線分割平面

①n條直線能把平面分成幾部分: 2+2+3+4......遞推公式 f(n)=f(n-1)+n

②一個圓與n條直線 這些直線中每一條在圓內同其他直線相交,假設沒有3條直線相交於一點,試問這些直線將圓分成多少區域:

與①相同

現在看下本題 平面的部分數與頂點即直線的交點有關 n=1時有2條線1個交點 部分為2 n=2時有3有4條線6個交點部分為7 所以n=n-1時有 2*(n-1)條線所以n=n時可增加2*2*(n-1)+1(本身的頂點)個部分

即遞推公式為 f(n)=f(n-1)+4*(n-1)+1;

codeforces 429B B. Working out

先處理出從左上到右下的最大值和左下到右上的最大值然後枚舉交點和進出的方向

技術分享
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int dp1[1010][1010],dp2[1010][1010],dp3[1010][1010],dp4[1010][1010];
int ans[1010][1010];
//(1,1)->(i,j)+(i,j)->(n,m)+(n,1)->(i,j)+(i,j)->(1,m);
int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&ans[i][j]); } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ dp1[i][j]=max(dp1[i-1][j],dp1[i][j-1])+ans[i][j]; } } for(int i=n;i>=1;i--){ for(int j=m;j>=1;j--){ dp2[i][j]=max(dp2[i+1][j],dp2[i][j+1])+ans[i][j]; } } for(int i=1;i<=n;i++){ for(int j=m;j>=1;j--){ dp3[i][j]=max(dp3[i-1][j],dp3[i][j+1])+ans[i][j]; } } for(int i=n;i>=1;i--){ for(int j=1;j<=m;j++){ dp4[i][j]=max(dp4[i][j-1],dp4[i+1][j])+ans[i][j]; } } int cnt=0; for(int i=2;i<n;i++){ for(int j=2;j<m;j++){ cnt=max(cnt,dp1[i-1][j]+dp2[i+1][j]+dp3[i][j+1]+dp4[i][j-1]); cnt=max(cnt,dp1[i][j-1]+dp2[i][j+1]+dp3[i-1][j]+dp4[i+1][j]); } } printf("%d\n",cnt); return 0; }
View Code

基礎簡單DP