##馬攔過河卒
[原題傳送門](
這一到題目也是比較基礎的動態規劃,也可以理解為是遞推,主要是運用加法原理,思維難度不大。我們要求從$(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 首先給出乙個正整...