動態規劃特訓:切蛋糕(UVA1629)
阿新 • • 發佈:2018-12-09
解題思路:利用動態規劃的思想,這裡的狀態即是蛋糕的上線、下線、左線、右線。然後進行記憶化搜素。遍歷豎著切的每一種方式和橫著切的每一種方式最終得到結果。狀態轉移方程稍微有些繁瑣,在這裡就不列舉了,可以直接看程式碼理解。
題目大意:給定一個方形蛋糕,上面有一些櫻桃,現在可以對該蛋糕做切割處理,保證切出來的每一份小蛋糕上都有一個櫻桃,且切割線的總長度最小。
Sample Input 3 4 3 1 2 2 3 3 2 Sample Output Case 1: 5
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int inf = 1 << 30; int n, m, k, dp[51][51][51][51]; //蛋糕尺寸和櫻桃數目,以及dp數值 bool mark[51][51]; //為true即表示該位置放有櫻桃 int sum(int s, int x, int z, int y) //此函式用來統計尺寸蛋糕內櫻桃的數目 { int ret = 0; for (int i = x; i <= s; i++) { for (int j = z; j <= y; j++) { if (mark[i][j] == true) ret++; } } return ret; } int f(int s, int x, int z, int y) { int &ans = dp[s][x][z][y]; if (ans != -1) return ans; int cherry = sum(s, x, z, y); if (cherry == 1) return ans = 0; //如果尺寸內只有一個櫻桃,則無需切割,直接返回0 ans = inf; for (int i = x; i <s; i++) { if (sum(i, x, z, y) == 0 || sum(s, i + 1, z, y) == 0) continue; //若選擇的切割方式切不出櫻桃,則放棄 ans = min(ans, f(i, x, z, y) + f(s, i + 1, z, y) + y - z+1); } for (int i = z;i < y; i++) { if (sum(s, x, z, i) == 0 || sum(s, x, i + 1, y) == 0) continue; //同理,切出的蛋糕無櫻桃則放棄 ans = min(ans, f(s, x, z, i) + f(s, x, i + 1, y) + s - x+1); } return ans; } int main() { while (cin >> n >> m) { cin >> k; memset(mark, false, sizeof(mark)); memset(dp, -1, sizeof(dp)); for (int i = 1; i <= k; i++) { int x, y; cin >> x >> y; mark[x][y] = true; } cout << f(n, 1, 1, m) << endl; } return 0; }