题目大意: 给你n天要穿的衣服,可以套着穿,但是一旦脱下来就不能载穿了,问n天至少需要多少衣服?
做了两个关于区间dp的题,遇到这个题还是不会做,网上搜了一下,感觉也不难,就是自己想不起来。。。
思路:dp[i][j]表示从第i天到第j天至少需要多少衣服,那么dp[i][j] = dp[i + 1][j] + 1,这是最坏情况,就是最多的一种,如果后面有跟第i个相同的,那么根本不许要这么多,只需要dp[i+1][j]中就够了,不用加这个1了,因为后面有跟他相同的,考虑第k天,那么就假设第k天与第i天相同,那么dp[i+1][j]就可以表示为dp[i+1][k-1] + dp[k][j], dp[i + 1][k - 1]表示从i+1天到k-1天最小需要,因为这个和k无关,所以不用管里面有没有相同的,但是后面这个dp[k][j]就有用了,就是说必须k天的跟i天的相同才可以这么拆,不然不能拆。所以状态转移方程就有了。dp[i][j]=min(dp[i][j], dp[i + ][k - 1] + dp[k][j]);
代码如下:
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int maxn = 110; const int inf = (1 << 30); int dp[maxn][maxn]; int a[maxn]; int main() { int T, n, kase = 0; scanf("%d", &T); while (T--) { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i <= n; i++)//初始化 for (int j = i; j <= n; j++) dp[i][j] = j - i + 1; for (int i = n - 1; i >= 1; i--)//从后往前推 { for (int j = i + 1; j <= n; j++) { dp[i][j] = dp[i + 1][j] + 1; for (int k = i + 1; k <= j; k++) if (a[i] == a[k]) dp[i][j] = min(dp[i][j], dp[i + 1][k - 1] + dp[k][j]); } } printf("Case %d: %d ", ++kase, dp[1][n]); } return 0; }
还有一点需要说明,在dp问题中,循环顺序是非常非常重要的,一定要搞清楚当前状态是从哪个状态过来的。而且从那个状态过来的时候,那个状态一定是计算过的。上面的就是从后往前推。下面还有一种解法,我个人感觉是非常自然的一个解法,就是状态转移方程比较贴切。
用dp[i][j]表示从第i天到第j天至少需要多少衣服,考虑第j天,如果在第j天的时候需要的衣服在i->j-1天里面如果没有就是dp[i][j] = dp[i][j - 1] + 1; 如果已经有了的话,那么dp[i][j] = dp[i][j - 1]; 假设在第k天和第j天的衣服相同,由于dp[i][j - 1] = dp[i][k] + dp[k + 1][j - 1]; 所以dp[i][j] = dp[i][k] + dp[k+1][j - 1];
代码如下:
#include <cstdio> #include <iostream> using namespace std; const int maxn = 110; int dp[maxn][maxn]; int a[maxn]; int main() { int T, n, kase = 0; scanf("%d", &T); while (T--) { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) dp[i][j] = j - i + 1; for (int j = 2; j <= n; j++)//区间右端点,顺序枚举 { for (int i = j - 1; i >= 0; i--)//左端点逆序 { dp[i][j] = dp[i][j - 1] + 1; for (int k = i; k < j; k++) if (a[k] == a[j]) dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j - 1]); } } printf("Case %d: %d ", ++kase, dp[1][n]); } return 0; }