1. 程式人生 > 實用技巧 >滾動陣列(細節)(坑點)

滾動陣列(細節)(坑點)

滾動陣列中本次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\)

,\(f[i][j][k]= = 0\)表示最後一個數一直加到\(a[i][j]\)(還沒加\(a[i][j]\))不能達到k,\(f[i][j][k] = = 1\)表示可以達到 \(k\)
我們不處理負數,所以對於\(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;
}