UVA 1629 Cake slicing
Answer key by ZhangXiubo
Personal blog : coldtea.tech
Key Point :
DP
Recursion
Sub-question
Why DP?
Every piece of cake has a similar state(Length and width, number of cherries)
Every state can transfer to another state, and with the process of the transfer, you can find the minimize length of cutting.
How to DP?
Firstly, we need to find the endding state, we can easily get if the number of cheeries on a piece of cake is one means the length of this piece of cake is 0.
then a piece of cake if is organized by two piece of cakes, I mean , you can get the the two piece of cakes by cutting this piece (emmmm we easily set it crosscut ). If this piece of cake left point is L , right point is R. The cutting worth (r-l) obviously.
You need to traverse all horizontal and vertical cuts at every step。
If you set upbound u , downbound d, leftbound l, right bound r,you will get the DP transfer formulars.
for (int i = u + 1; i <= d; i++)
{
ans = min(ans, DP(u, i, l, r) + DP(i, d, l, r) + r - l);// interaion all the Upright
}
for (int i = l + 1; i <= r; i++)
{
ans = min(ans, DP(u, d, l, i) + DP(u, d, i, r) + d - u);
//interation all the Sideways
}
Memory search
If you always play fib sequences and use recursion to handle it , you will find the programme will be unbearably slow.The reason is you did plenty of repeated work.
But you can open an extra array to store what you have calculated .
If you need to call it ,you don’t need to calculate again but to load from your array.
code
#include<bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false) //close synchronize
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 20 + 4;
int dp[maxn][maxn][maxn][maxn]; present upbound u , downbound d, leftbound l, right bound r.
int n, m, k;
int cherry[maxn][maxn];//cheery laocation
int sum_cherry(int u, int d, int l, int r)// present upbound u , downbound d, leftbound l, right bound r.
{
int ans = 0;
for (int i = u + 1; i <= d; i++)
{
for (int j = l + 1; j <= r; j++)
{
if (cherry[i][j] == 1)
ans++;
if (ans == 2)return ans;//if the number>=2 we should take them out
}
}
return ans;
}
int DP(int u, int d, int l, int r)
{
int& ans = dp[u][d][l][r];
if (ans != -1)
return dp[u][d][l][r];//memery search
int tot = sum_cherry(u, d, l, r);
if (tot == 0)return ans = INF;//
if (tot == 1)return ans = 0;//if last is one return 0
ans = INF;
for (int i = u + 1; i <= d; i++)//
{
ans = min(ans, DP(u, i, l, r) + DP(i, d, l, r) + r - l);// interaion all the Upright
}
for (int i = l + 1; i <= r; i++)
{
ans = min(ans, DP(u, d, l, i) + DP(u, d, i, r) + d - u);//interation all the Sideways
}
return ans;
}
int main()
{
ios;
int index = 1;
while (cin>>n>>m>>k)
{
int u; int v;
memset(cherry, 0, sizeof(cherry));
for (int i = 0; i < k; i++)
{
cin >> u >> v;
cherry[u][v] = 1;//that point has one cherry
}
memset(dp, -1, sizeof(dp));
int ans = DP(0, n, 0, m);
cout << "Case " << index++ << ": " << ans << "\n";
}
return 0;
}