平面二維DP

2022-04-01 05:40:21 字數 3886 閱讀 7344

##馬攔過河卒

[原題傳送門](

這一到題目也是比較基礎的動態規劃,也可以理解為是遞推,主要是運用加法原理,思維難度不大。我們要求從$(0,0)$到$(n,n)$的方案總數,如果沒有馬的話,我們可以這麼做:

設$f[i][j]$為從$(0,0)$走到$(i,j)$的方案總數,我們知道一定是有上面和左邊走來,所以只需要累加上面和左邊的方案數即可。我們得出:$$f[i][j]=f[i-1][j]+f[i][j-1](f[0][0...m]=f[0...n][0]=1)$$

我們來思考一下馬的問題:

1.當馬攔住了$(0,0...m)$或$(0...n,0)$的時候,攔住的且後面的必然走不到,所以停止賦值

2.如果馬攔住了$(x,y)$$(x≠0,y≠0)$,則不進行狀態轉移即可

**如下:

#includeusing namespace std;

int main()

; int dx[9]=;

int dy[9]=;

for (int i=1;i<=9;i++)

int find[20][20]={};

for (int i=0;i<=b2;i++)

if (vis[0][i]==0)

find[0][i]=1;

else

for (int i=0;i<=b1;i++)

if (vis[i][0]==0)

find[i][0]=1;

else

for (int x=1;x<=b1;x++)

for (int y=1;y<=b2;y++)

if (vis[x][y]==0)

find[x][y]=find[x-1][y]+find[x][y-1];

cout《你的老家在農村。過年時,你回老家去拜年。你家有一片n×mn×m農田,將其看成乙個n×mn×m的方格矩陣,有些方格是一片水域。你的農村伯伯聽說你是學計算機的,給你出了一道題: 他問你:這片農田總共包含了多少個不存在水域的正方形農田。

兩個正方形農田不同必須至少包含下面的兩個條件中的一條:

1 邊長不相等

2 左上角的方格不是同一方格

輸入資料第一行為兩個由空格分開的正整數n、m(1<=m< n <=1000)

第2行到第n+1行每行有m個數字(0或1),描述了這一片農田。0表示這個方格為水域,否則為農田(注意:數字之間沒有空格,而且每行不會出現空格)

滿足條件的正方形農田個數。

input

3 3110

110000

output

5樣例解釋 邊長為1的正方形農田有4塊 邊長為2的正方形農田有1塊 合起來就是5塊

時間限制:1s

空間限制:256mb

求多少個正方形,我們設\(f[i][j]\)為以\((i,j)\)為右下角的正方形個數。如果你畫過圖,就能夠發現:右下角的個數就是以這個點右下角的最大正方形,因為大正方形包含了無數個小正方形,基於正方形的特殊性,我就不難知道這乙個性質。然後我們就去考慮,如何去轉移,再通過畫圖可以發現:這個點所能形成的最大正方形與左邊的點,左上角的點和上面的點所能形成的最大正方形的個數的最小值有關,也就是\(min(f[i-1][j],f[i][j-1],f[i-1][j-1])\)。那麼這個數值具體是多少呢?就是這個數值\(+1\);即在原來形成的正方形的基礎上加上了這個右下角。因此,我們可以得到:$$f[i][j]=min(f[i-1][j],f[i][j-1],f[i-1][j-1])+1$$

**如下:

#includeusing namespace std;

int n,m,ans=0;

int f[5000][5000];

char a[5000][5000];

inline int min(int a,int b,int c)

int main()

f[i][k]+f[i][j-k], k=1...m/2 \\

f[k][j]+f[i-j][j], k=1...n/2\\

\end

\]因為對稱所以k只需要列舉到\(n(m)/2\)

#includeusing namespace std;

int f[120][120];

inline int min(int a,int b)

inline int read(int &k)

inline void readln(int &x,int &y)

void print(int x)

if (x>=10) print(x/10);

putchar(x%10+'0');

}int main()

print(f[n][m]);putchar('\n');

fclose(stdin);fclose(stdout);

return 0;

}

原題傳送門②

思路:同樣我們設\(f[i][j]\)為\(i,j\)為右下叫的最大吃魚方陣。模擬一下農田個數,這乙個方陣的最大值其實就和左邊連續\(0\)的個數和上面連續\(0\)的個數和左上角的最大方陣;因為根據規則,左邊和上面必須是\(0\),因此就與\(0\)的個數有關;又要除了這一串\(0\)之外,還和左上角的有關有關,這一點又和左上角的方陣有關。我們再做乙個字首和,則\(left[i][j]\)表示\((i,j)\)為右下腳且不包括本身的連續0個數,up意義同上。這裡不做過多論述:$$f[i][j]=min(left[i][j],up[i][j],f[i-1][j-1)+1$$至於另乙個方向,按照同樣的方法做一遍即可。

**如下:

#includeusing namespace std;

int ans=0;

int f[3000][3000];

int g[3000][3000];

int up[3000][3000];

int map[3000][3000];

int left[3000][3000];

int right[3000][3000];

inline int min(int a,int b)

inline int max(int a,int b)

inline int min(int a,int b,int c)

inline int max(int a,int b,int c)

inline int read(int &k)

inline void readln(int &x,int &y)

void print(int x)

if (x>=10) print(x/10);

putchar(x%10+'0');

}int main()

{ freopen("meal.in","r",stdin);

freopen("meal.out","w",stdout);

int n,m;readln(n,m);

for (register int i=1;i<=n;++i)

for (register int j=1;j<=m;++j)

read(map[i][j]);

for (register int i=1;i<=n;++i)

for (register int j=2;j<=m;++j)

if (!map[i][j-1]) left[i][j]=left[i][j-1]+1;

for (register int j=1;j<=m;++j)

for (register int i=2;i<=n;++i)

if (!map[i-1][j]) up[i][j]=up[i-1][j]+1;

for (register int i=1;i<=n;++i)

for (register int j=m-1;j;--j)

if (!map[i][j+1]) right[i][j]=right[i][j+1]+1;

//cout<

完美序列(二維dp)

題目描述 已知乙個長度為l的序列 b1,b2,b3,bl 1 b1 b2 b3 bl n 若這個序列滿足每個元素是它後續元素的因子,換句話說就是對於任意的i 2 i l 都滿足bi bi 1 0 其中 代表求餘 則稱這個序列是完美的。你的任務是對於給定的n和l,計算出一共有多少序列是完美序列。由於答...

二維取數dp

acwing 1027.方格取數 對於走一次,容易得到狀態轉移方程為 f i j max f i 1 j f i j 1 w i j 而對於走兩次時,設定狀態為 f i 1 j 1 i 2 j 2 表示第一條路徑從 1,1 走到 i 1,j 1 第二條路徑從 1,1 走到 i 2,j 2 取的數的最...

hdu 2563 二維平面移動

在一無限大的二維平面中,我們做如下假設 1 每次只能移動一格 2 不能向後走 假設你的目的地是 向上 那麼你可以向左走,可以向右走,也可以向上走,但是不可以向下走 3 走過的格仔立即塌陷無法再走第二次 求走n步不同的方案數 2種走法只要有一步不一樣,即被認為是不同的方案 input 首先給出乙個正整...