到达型dp
一般将dp数组设为bool型,常用位运算| 实现状态的传递。
P2663 越越的组队
本题状态设计很特殊:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示前
i
i
i个人能否达到
j
j
j分。
bool dp[110][11000];
int main(){
cin>>n;
dp[0][0]=1;
for(int i=1;i<=n;i++){
cin>>a[i]; sum+=a[i];
}
for(int i=1;i<=n;i++){
for(int j=i;j>=1;j--){
for(int k=sum>>1;k>=a[i];k--){
dp[j][k]|=dp[j-1][k-a[i]]; //类似于01背包 不加第i个人和加第i个人取或
}
}
}
for(int i=sum>>1;i>=0;i--){
if(dp[n>>1][i]){
printf("%d",i);return 0;
}
}
}
P1877 [HAOI2012]音量调节
状态表示:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 前
i
i
i场演出的音量能否达到
j
j
j。
本题要特别注意边界
bool dp[N][N];
int main(){
scanf("%d%d%d",&n,&st,&mx);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
dp[0][st]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=mx;j++){
if(j>=c[i]) dp[i][j]|=dp[i-1][j-c[i]]; //不小于0
if(j+c[i]<=mx) dp[i][j]|=dp[i-1][j+c[i]]; //不大于mx
}
}
for(int i=mx;i>=0;i--){
if(dp[n][i]){
printf("%d",i);return 0;
}
}
printf("-1");
}
在状态转移的过程中加限定条件,是为了防止错误的状态被转移到结果状态的位置,将正确答案覆盖掉。因此动态规划一定要注意边界和不合法情况的判定。