滾動數組優化陷阱

昨晚contest的Problem E,freezhan學姐用揹包寫AC了,但是優化成一維後連樣例都過不了,然後我就研究了一下。

這是優化前的代碼:

		F[0][0]=1;
		for(int i=1;i<=N;++i)
		{
			for(int j=M;j>=A[i];--j)
			{
				for(int k=A[i];k<=B[i]&&k<=j;++k)
				{
					F[i][j]+=F[i-1][j-k];
				}
			} 
		}

我想肯定有不少人會像我和freezhan學姐一樣把這份代碼優化爲:

		F[0]=1;
		for(int i=1;i<=N;++i)
		{
			for(int j=M;j>=A[i];--j)
			{
				for(int k=A[i];k<=B[i]&&k<=j;++k)
				{
					F[j]+=F[j-k];
				}
			} 
		}
對拍,測試,調整,完事發現這個問題很久之前就注意到了卻沒重視,看來以後哪個小問題都不能放過!

優化出錯的根本原因是滾動數組的不完全覆蓋

大多數的揹包問題最高維(一般就是物品編號)的每一次循環求解的第二維區間(一般就是[0,揹包容量])都是相同的。

如果用滾動數組優化成一維,每一次循環之後當前數據會完全覆蓋之前的數據,下一次循環時調用的數據就全部是更新了

的數據。

但是本題的最高維(i)的每一次循環求解的第二維區間([A[i],M])卻不盡相同!

如果用滾動數組優化成一維,每一次循環之後當前數據可能僅會部分覆蓋之前的數據!這就造成了數據殘留,下一次

循環時調用的數據就可能是殘留數據!

正確的做法應該是用滾動數組優化成二維:

		int roll=0;
		memset(F[roll],0,sizeof(F[roll]));
		F[roll][0]=1;
		for(int i=1;i<=N;++i)
		{
			roll=!roll;
			memset(F[roll],0,sizeof(F[roll]));
			for(int j=M;j>=A[i];--j)
			{
				for(int k=A[i];k<=B[i]&&k<=j;++k)
				{
					F[roll][j]+=F[!roll][j-k];
				}
			} 
		}

發佈了111 篇原創文章 · 獲贊 0 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章