LightOJ - 1422 (区间DP)
题意:有t组数据,对于每组,有n个聚会需要参加,下面依次是参加各个聚会需要的衣服编号,要求所需要的衣服一定穿在外面,在操作的时候,可以选择穿上一件衣服或脱下一件衣服,脱下的衣服不能继续使用,问最少需要的衣服数量。
分析:在穿第j件衣服的时候,我们需要知道原先的状态是否穿着第j件衣服,所以我们需要枚举所有间断的区间,需要用到区间dp
dp[i][j]代表,从第i个聚会到第j个聚会需要的最少的衣服数量
dp[i][j]最坏情况是第j件衣服是新穿的,dp[i][j]=dp[i][j-1]+1;
然后依次枚举k,如果第k件衣服和j件衣服相同
那么 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j-1]) (dp[i][k]保证最后一定有第k件衣服给第j次)
代码如下:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <vector> using namespace std; #define INF 0x3f3f3f3f int dp[110][110]; int a[110]; int t,n,Case=0; int main() { scanf("%d",&t); while(t--) { Case++; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(i==j)dp[i][j]=1; else if(i>j)dp[i][j]=0; else dp[i][j]=INF; } for(int l=1;l<=n-1;l++) for(int i=1;i<=n-l;i++) { int j=l+i; dp[i][j]=dp[i][j-1]+1; for(int k=i;k<j;k++) { if(a[j]==a[k]) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j-1]); } } printf("Case %d: %d\n",Case,dp[1][n]); } return 0; }