好题
poj 1141 Brackets Sequence 括号匹配并输出方案
洛谷2858 奶牛零食 区间长度逐渐缩小
洛谷1622 释放囚犯 将问题向区间DP转化的思想
参考博客:剑锋OI博客动态规划之区间DP专题
区间DP小结
区间DP常用模板
/* 初始化dp数组及len为1的情况*/
for(int len=2;len<=n;len++){//枚举长度
for(int l=1;l<=n-len+1;l++){//状态,区间左端点
int r=l+len-1;
for(int j=l;j<r;j++){//枚举断点
//转移方程决策
}
}
}
重点是区分阶段、状态、决策,以及状态转移方程的实现。
1、【HDU4745】Two Rabbits
求最大非连续回文串
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1005
#define INF 1e9
using namespace std;
int n,dp[2*N][2*N],a[2*N];
int main()
{
while(cin>>n&&n){
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
cin>>a[i];
a[i+n]=a[i];
dp[i][i]=dp[i+n][i+n]=1;
}
for(int len=2;len<=n;len++){
for(int l=1;l<=2*n-len+1;l++){
int r=l+len-1;
if(a[l]==a[r]) dp[l][r]=max(dp[l][r],dp[l+1][r-1]+2);
dp[l][r] = max(dp[l][r], max(dp[l+1][r], dp[l][r-1]));
}
}
int ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,dp[i][i+n-1]);
ans=max(ans,dp[i][i+n-2]+1);
}
cout<<ans<<endl;
}
}
2、【POJ1141】Brackets Sequence 括号匹配
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
#define N 105
#define INF 1e9
int d[N][N];
int pos[N][N];
char s[N]; //接受初始数据
void output(int l,int r)
{
if(l==r){
if(s[l]=='('||s[l]==')') cout<<"()";
else cout<<"[]";
return ;
}
if(l<r){
if(pos[l][r]==-1)
{
cout<<s[l];
output(l+1,r-1);
cout<<s[r];
}
else {
output(l,pos[l][r]);
output(pos[l][r]+1,r);
}
}
}
int main()
{
cin>>s;
int n=strlen(s)-1;
for(int i=0;i<=n;i++){
d[i][i]=1;
}
for(int len=2;len<=n+1;len++){
for(int l=0;l<=n-len+1;l++){
int r=l+len-1;
d[l][r]=INF;
if((s[l]=='('&&s[r]==')')||(s[l]=='['&&s[r]==']'))
{
d[l][r]=d[l+1][r-1];
pos[l][r]=-1;
}
for(int j=l;j<r;j++){
if(d[l][r]>(d[l][j]+d[j+1][r])){
d[l][r]=d[l][j]+d[j+1][r];
pos[l][r]=j;
}
}
}
}
output(0,n);
cout<<endl;
return 0;
}
下面的两道题目比较难搞,不能明显的看出是区间DP,一看上去,还以为贪心。划分好阶段、状态以后,转移方程需要好好的想想。
【洛谷1622】释放囚犯
#include<bits/stdc++.h>
#define N 1001
using namespace std;
int n,m,ans,a[N],sum[101],dp[N][N];
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++) cin>>a[i];
a[++m]=n+1;
sort(a+1,a+m+1);
for(int i=1;i<=m;i++){
sum[i]=sum[i-1]+a[i]-a[i-1]-1;
}
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=m;i++){
dp[i][i]=0;
}
for(int len=2;len<=m;len++)
{
for(int l=1;l+len-1<=m;l++){
int r=l+len-1;
for(int j=l;j<=r;j++){
dp[l][r]=min(dp[l][r],dp[l][j]+dp[j+1][r]+sum[r]-sum[l-1]+r-l-1);
}
}
}
cout<<dp[1][m];
}
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 51
using namespace std;
int n,a[N],b[N],c,dp[N][N][2],sum[N];
int main()
{
cin>>n>>c;
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i];
sum[i]=sum[i-1]+b[i];
}
dp[c][c][1]=dp[c][c][0]=0;
for(int len=2;len<=n;len++){
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
for(int k=l;k<r;k++){
dp[l][r][0]=min(dp[l+1][r][0]+(a[l+1]-a[l])*(sum[l]+sum[n]-sum[r]),dp[l+1][r][1]+(a[r]-a[l])*(sum[l]+sum[n]-sum[r]));
dp[l][r][1]=min(dp[l][r-1][0]+(a[r]-a[l])*(sum[n]+sum[l-1]-sum[r-1]),dp[l][r-1][1]+(a[r]-a[r-1])*(sum[n]+sum[l-1]-sum[r-1]));
}
}
}
int ans=min(dp[1][n][1],dp[1][n][0]);
cout<<ans<<endl;
}