洛谷P1174 打磚塊 | CCPC2021網路賽8.28 1011 動態規劃 分組揹包
阿新 • • 發佈:2021-09-01
本文學習自洛谷社群
喜提CCPC2021網路賽原題
題意相當於是要在每一列中選若干個磚塊打掉,消耗所需的子彈數並得到對應的得分。最大化k個子彈能得到的最大得分。
預處理出第 \(i\) 列 \(j\) 個子彈能得到的最大得分,記為\(sum[i][j]\),那麼這可以轉為一個分組揹包問題。但一個小問題是,在沒有子彈時,你不能在打掉'Y'格,因此我們需要追蹤最後一發子彈的去向。
記\(sum[i][j][0]\)表示第\(i\)列用\(j\)個子彈,全域性的最後一發子彈不打在這一列能得到的最大得分,\(sum[i][j][1]\)表示第\(i\)列用\(j\)個子彈,全域性的最後一發子彈打在這一列的最大得分。
最後一發子彈沒有打在這一列的話,預處理時能從第\(n\)行不斷往上爬直到無法爬為止,遇到'Y'就能以0的代價拿下。但若最後一發子彈打在這一列,碰上'N'時,\(sum[i][j][1]\)需要用s\(um[i][j−1][0]\)更新。據此可以寫出預處理程式碼如下:
for (int i = 1; i <= m; i++) { for (int j = n, cnt = 0; j >= 1; j--) { if (c[j][i] == 'Y') { sum[i][cnt][0] += a[j][i]; } else { cnt++; sum[i][cnt][0] = sum[i][cnt-1][0] + a[j][i]; sum[i][cnt][1] = sum[i][cnt-1][0] + a[j][i]; } } }
然後考慮修改後的“分組揹包”。記\(dp[i][j][0]\)表示前\(i\)列\(j\)發子彈,最後一發子彈不打在前i列能得到的最大得分,\(dp[i][j][1]\)表示前\(i\)列\(j\)發子彈,最後一發子彈打在前\(i\)列能得到的最大得分。轉移有如下幾種:
1.最後一發打在當前列,即\(l>0\)
dp[i][j][1] = max(dp[i][j][1], dp[i-1][j-l][0]+sum[i][l][1]);
2.最後一發打在前\(i\)列,但不是當前列,即\(j−l>0\)
dp[i][j][1] = max(dp[i][j][1], dp[i-1][j-l][1]+sum[i][l][0]);
3.最後一發不打在前ii列
dp[i][j][0] = max(dp[i][j][0], dp[i-1][j-l][0]+sum[i][l][0]);
for (int i = 1; i <= m; i++) {
for (int j = 0; j <= k; j++) { //一共有j發子彈
for (int l = 0; l <= min(j, n); l++) { //嘗試在這一列打l發
//case 3
dp[i][j][0] = max(dp[i][j][0], dp[i-1][j-l][0]+sum[i][l][0]);
if (l) { //case 1
dp[i][j][1] = max(dp[i][j][1], dp[i-1][j-l][0]+sum[i][l][1]);
}
if (j-l) { //case 2
dp[i][j][1] = max(dp[i][j][1], dp[i-1][j-l][1]+sum[i][l][0]);
}
}
}
}
然後就可以過了。
The desire of his soul is the prophecy of his fate
你靈魂的慾望,是你命運的先知。