RQNOJ273 马棚问题(DP)

题意分析

状态设计

dp[i][j] d p [ i ] [ j ] 表示对于前i个马棚, 装前j匹马的不愉快系数的最小值。

状态转移方程

dp[i][j]=min(dp[i][j],dp[i1][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,在所有可能的情况中取得一个最小值即可。

注意的地方

  1. 首先就是循环的时候,可以注意到对于j < i是没有意义的,因为题目要求不能有空马棚,所以对于i个马棚,至少有j匹马来装。
  2. 在枚举分界点j的时候,如果不细致考虑,可以让其从1到n-1依次枚举。首先说为什么枚举终点是n-1,还是因为那个原因,马棚不允许空,也就是后面一定要分到一匹马。 然后再说枚举起点,准确来说枚举起点应该是i-1,原因也是马棚不能为空,因为我们状态转移方程考虑的是前i-1个马棚,至少要分到i-1匹马。

代码总览

#include
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;
}

你可能感兴趣的:(算法---动态规划)