LightOJ 1422 Halloween Costumes 区间dp
题意:给你n天需要穿的衣服的样式,每次可以套着穿衣服,脱掉的衣服就不能再穿了,问至少要带多少条衣服才能参加所有宴会
思路:dp[i][j]代表i-j天最少要带的衣服
从后向前dp 区间从大到小
更新dp[i][j]时有两种情况 考虑第i天穿的衣服
1:第i天穿的衣服在之后不再穿了 那么 dp[i][j]=dp[i+1][j]+1;
2:第i天穿的衣服与i+1到j的某一天共用,那么dp[i][j]=min(dp[i][j],dp[i+1][k-1],dp[k][j]),前提是第i天和第k天需要的礼服样式相同
代码如下(注意dp的初始化和方向)
http://lightoj.com/volume_showproblem.php?problem=1422 #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cstdlib> #include<cmath> using namespace std; typedef long long LL; int dp[105][105],a[105]; int main() { int T,cas=0; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d",&a[i]); memset(dp,0,sizeof(dp)); 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;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\n",++cas,dp[1][n]); } return 0; }
普通的区间dp写法,上面那种其实也行,主要是我喜欢普通的区间dp写法
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cstdlib> #include<cmath> using namespace std; typedef long long LL; int dp[105][105],a[105]; int main() { int T,cas=0; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=1; i<=n; ++i) scanf("%d",&a[i]); memset(dp,0,sizeof(dp)); for(int i=1; i<=n; ++i) for(int j=i; j<=n; ++j) dp[i][j]=j-i+1; for(int k=1; k<n; ++k) { for(int i=1; i+k<=n; ++i) { dp[i][i+k]=dp[i+1][i+k]+1; for(int j=i+1; j<=i+k; ++j) if(a[i]==a[j]) dp[i][i+k]=min(dp[i][i+k],dp[i+1][j-1]+dp[j][i+k]); } } printf("Case %d: %d\n",++cas,dp[1][n]); } return 0; }