方格DP之MICE
阿新 • • 發佈:2020-07-09
題目
思路
有點水的DP,本來想寫二維,\(f[i][j]\)代表在第i行第j列的最優解,顯然,這樣寫對於我這個蒟蒻來說很難,所以改成了三維\(f[i][j][k]\),表示在第i行第j列,k用來表示從哪一狀態轉移過來,\(k=1\)代表從左邊(即\(i,j-1\))轉移過來,\(k=2\)代表從上面(即\(i-1,j\))轉移過來,當前狀態轉移,只與上一狀態和上上狀態有關,結合圖形,我們可以推得以下公式
f[i][j][1]=min(f[i][j-1][1]+a[i-1][j]+a[i+1][j]+a[i][j+1],f[i][j-1][2]+a[i][j+1]+a[i+1][j]); f[i][j][2]=min(f[i-1][j][2]+a[i][j-1]+a[i][j+1]+a[i+1][j],f[i-1][j][1]+a[i][j+1]+a[i+1][j]);
舉個栗子,對於\(f[i][j][1]\)來說,它由\(f[i][j-1][1]\)和\(f[i][j-1][2]\)轉移過來,一種是三個狀態(當前狀態,上一狀態,和上上狀態)橫著排列,那麼最新看到的老鼠為\(a[i-1][j]\),\(a[i+1][j]\),\(a[i][j+1]\),另一種狀態是上一狀態由上上狀態向下轉移,當前狀態由上一狀態向右轉移,那麼新看到的老鼠只有\(a[i][j+1]\),\(a[i+1][j]\),很明顯就可以看出來。
關於初始化,將f陣列初始化為無窮大,dp的時候在\((1,1)\)的位置特判一下就ok了
下面是程式碼(帶註釋)
#include<bits/stdc++.h> using namespace std; const int maxn=1000+10; int f[maxn][maxn][2];//維護三維dp陣列 int a[maxn][maxn]; 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",&a[i][j]); } } memset(f,0x7f,sizeof(f));//初始化 for(int i=1;i<=n;i++){//列舉行數 for(int j=1;j<=m;j++){//列舉列數 if(i==1&&j==1){//特殊處理一下 f[i][j][1]=a[i][j]+a[i+1][j]+a[i][j+1]; f[i][j][2]=a[i][j]+a[i+1][j]+a[i][j+1]; } else{//進行轉移 f[i][j][1]=min(f[i][j-1][1]+a[i-1][j]+a[i+1][j]+a[i][j+1],f[i][j-1][2]+a[i][j+1]+a[i+1][j]); f[i][j][2]=min(f[i-1][j][2]+a[i][j-1]+a[i][j+1]+a[i+1][j],f[i-1][j][1]+a[i][j+1]+a[i+1][j]); } } } printf("%d\n",min(f[n][m][2],f[n][m][1]));//最後在(n,m)位置的兩個狀態中取個最小值就ok了 }