滾動陣列(細節)(坑點)
滾動陣列中本次0/1用完後,對後面結果無貢獻了,一定要記得清零,否則會不斷累積(一共就兩個數0/1,迴圈多了肯定都快填滿了)
那道題是這樣的:(步步為零)
步步為零(dp ⋆⋆)
你是否聽說過這個遊戲?遊戲者在一張特殊的表格中按照規則跳動,使得跳到的數字經過加號和減號的連線,儘可能的逼近零。表格通常是如圖 1.1所示的形狀,大小由中間一行的方格數 N 決定(圖 1.1 就是一個 N=4的例子)。
遊戲者通常是從最下面的方格出發,按照如圖 1.2所示的規則在表格中跳動,當遊戲者跳到最頂端的方格時,遊戲結束。在遊戲未結束前,遊戲者不允許跳到表格外。將遊戲者跳到的 2∗N−1個數字依次寫下來,在每兩個相鄰的數字中間加上加號或減號,使得計算結果最接近零。例如對於圖 1.1所示的表格,最好的跳動及計算方案是:\(7+8+(−5)+(−2)−5−1−2=0 或 7+10+(−7)−6+(−3)−3+2=0 或 7+10+(−5)−10−5+1+2=0 或 7+10+(−5)+(−2)−5−3−2=0。\)
Input
輸入檔案的第一行是 \(N(N<=50)\),接下來 \(2∗N−1\) 行給出了表格中每行的每個方格中的數字,第 \(i+1\) 行的第 \(j\) 個數字對應於表格中第 \(i\) 行的第 \(j\) 個數字。檔案中第二行的數字表示的是表格頂端的方格中的數字。檔案中所有的數字都是整數,同一行相鄰的兩個數字間用空格符隔開。
Output
輸出檔案只有一行,是你所求出的最接近零的計算結果的絕對值。
Sample Input
4
2
3 1
-3 5 7
6 10 -2 20
-7 -5 -8
10 8
7
Sample Output
0
Hint
表格中的所有數字大於等於−50,小於等於50。
(本部落格主要強調細節,好吧寫完部落格之後我覺得上句話並不恰當)
\(f[i][j][k]= 0 或 1\)
我們不處理負數,所以對於\(k\),我們算出一個最大區間\([-mid,mid]\),然後每次求出來的和都向上平移mid以保證正數。
轉移:(我們是從下向上轉移/遞推)
- 對於下半部分 由 \(f[i][j][k] = = 1\) 可以得到
\(-> f[i-1][j][k+a[i][j]] = 1;\)
\(-> f[i-1][j+1][k+a[i][j] = 1;\)
\(-> f[i-1][j][k-a[i][j]] = 1;\)
\(-> f[i-1][j+1][k-a[i][j] = 1;\) - 對於上半部分,同理:由 \(f[i][j][k] = = 1\) 可以得到
\(-> f[i-1][j][k+a[i][j]] = 1;\)
\(-> f[i-1][j-1][k+a[i][j] = 1;\)
\(-> f[i-1][j][k-a[i][j]] = 1;\)
\(-> f[i-1][j-1][k-a[i][j] = 1;\)
最後統計第0行的結果,不統計第一行是因為 \(f[1][1][k]\) 還沒有算上 \(a[1][1]\) ,算上 \(a[1][1]\) 的結果轉移到f[0][1][k]和 \(f[0][0][k]\) 中了。
每階段只與上一階段相關,滾動陣列壓維,每次轉移完後沒用了注意清零。
Code
#include <cstdio>
#include <algorithm>
using namespace std;
int Max,mid,n,st,a[52][52],f[2][52][10000];
int A(int x){
return x>=0?x:-x;
}
int main(){
// freopen("1.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;++i){
Max=0;
for(int j=1;j<=i;++j){
scanf("%d",&a[i][j]);
a[i][j]=A(a[i][j]);
Max=a[i][j]>Max?a[i][j]:Max;
}
mid+=Max;
}
for(int i=1;i<n;++i){
Max=0;
for(int j=1;j<=n-i;++j){
scanf("%d",&a[n+i][j]);
a[n+i][j]=A(a[n+i][j]);
Max=a[n+i][j]>Max?a[n+i][j]:Max;
}
mid+=Max;
}
int next;
f[st][1][mid]=1;
for(int i=n*2-1;i>=n;--i,st^=1){
for(int j=1;j<=(n<<1)-i;++j){
for(int k=0;k<=(mid<<1);++k){
if(f[st][j][k]){
next=k+a[i][j];
f[st^1][j][next]=f[st^1][j+1][next]=1;
next=k-a[i][j];
f[st^1][j][next]=f[st^1][j+1][next]=1;
f[st][j][k]=0;//記得清零aaaaa
}
}
}
}
for(int i=n-1;i>=1;--i,st^=1){
for(int j=1;j<=i;++j){
for(int k=0;k<=(mid<<1);++k){
if(f[st][j][k]){
next=k+a[i][j];
f[st^1][j][next]=f[st^1][j-1][next]=1;
next=k-a[i][j];
f[st^1][j][next]=f[st^1][j-1][next]=1;
f[st][j][k]=0;//記得清零aaaaa
}
}
}
}
int ans=0x3f3f3f3f;
for(int i=0;i<=(mid<<1);++i){
if(f[st][1][i])ans=ans<A(mid-i)?ans:A(mid-i);
}
printf("%d\n",ans);
return 0;
}