题意分析
状态设计
dp[i][j] d p [ i ] [ j ] 表示对于前i个马棚, 装前j匹马的不愉快系数的最小值。
状态转移方程
dp[i][j]=min(dp[i][j],dp[i−1][k]+cost[k+1][j])
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
−
1
]
[
k
]
+
c
o
s
t
[
k
+
1
]
[
j
]
)
对于前i个马棚,装前j匹马的不愉快叙述, 可以考虑对于前i-1个马棚,装前k匹马,然后剩下的一个马棚装k+1到j匹马。 枚举分界点k,在所有可能的情况中取得一个最小值即可。
注意的地方
- 首先就是循环的时候,可以注意到对于j < i是没有意义的,因为题目要求不能有空马棚,所以对于i个马棚,至少有j匹马来装。
- 在枚举分界点j的时候,如果不细致考虑,可以让其从1到n-1依次枚举。首先说为什么枚举终点是n-1,还是因为那个原因,马棚不允许空,也就是后面一定要分到一匹马。 然后再说枚举起点,准确来说枚举起点应该是i-1,原因也是马棚不能为空,因为我们状态转移方程考虑的是前i-1个马棚,至少要分到i-1匹马。
代码总览
#include<bits/stdc++.h>
using namespace std;
const int nmax = 505;
const int INF = 0x3f3f3f3f;
int a[nmax];
int c1[nmax],c0[nmax];
int dp[nmax][nmax];
int n,m;
int cost(int k,int j){
return (c1[j] - c1[k-1]) * (c0[j] - c0[k-1]);
}
int main(){
while(scanf("%d %d",&n,&m)!=EOF){
for(int i = 1;i<=n;++i){
scanf("%d",&a[i]);
if(a[i] == 1) c1[i] = c1[i-1] + 1;
else c1[i] = c1[i-1];
if(a[i] == 0) c0[i] = c0[i-1] + 1;
else c0[i] = c0[i-1];
}
for(int i = 1;i<=n;++i) dp[1][i] = c1[i] * c0[i];
for(int i = 2;i<=m;++i){
for(int j = i;j<=n;++j){
dp[i][j] = INF;
for(int k = 1;k<=n-1;++k){
if(k>=i-1)
dp[i][j] = min(dp[i][j],dp[i-1][k] + cost(k+1,j));
}
}
}
int ans = dp[m][n];
printf("%d\n",ans);
}
return 0;
}