Jzoj P5535 [2014东莞市选]登机___动态规划

题目大意:

飞机上的座位有S行,编号从1到s,每行有六个座位,标记为A到F。
有n个乘客陆续登机,第 i i i名乘客的座位在第 R i R_i Ri行,
i i i名乘客的登机难度等于在他登机时坐在 1 , 2 , . . . , R i − 1 1,2,...,R_{i}-1 1,2,...,Ri1行的乘客的人数。
现在将飞机座位划分为 k k k个区域。每一个区域必须是连续的行。
划分成 k k k个区域之后,乘客的登机顺序不会改变,但是每个乘客的登机难度将只统计该乘客所在区域前面乘客的人数。
问如何划分这k个区域,才能让乘客的登机难度总和最少。
求这个最小难度总和。

1 ≤ R i ≤ S 1≤Ri≤S 1RiS
n < = 1000 , s < = 1000 , k < = 50 , k < = s n<=1000,s<=1000, k<=50, k<=s n<=1000s<=1000,k<=50,k<=s

分析:

n u m i , j num_{i,j} numi,j表示前 j j j行的人对第 i i i行的人的登机难度的贡献( j < = i j<=i j<=i)
然后这个可以 O ( S 2 ) O(S^2) O(S2)处理
我们再设 s u m i , j sum_{i,j} sumi,j表示第 i i i行到第 j j j行的人划为一个区域时的登机难度总和,
可推出: s u m i , j = s u m i , j − 1 + ( n u m j , j − n u m j , i − 1 ) sum_{i,j}=sum_{i,j-1}+(num_{j,j}-num_{j,i-1}) sumi,j=sumi,j1+(numj,jnumj,i1)
求这个也是 O ( S 2 ) O(S^2) O(S2)
d p i , j dp_{i,j} dpi,j表示前 i i i行分成了 j j j个区域时人的最小登机难度总和,
则我们枚举一个 k k k,使前 k k k行分 j − 1 j-1 j1个区域,
则可以转移 d p i , j = m i n ( d p i , j , d p i , k + s u m k + 1 , i ) dp_{i,j}=min(dp_{i,j},dp_{i,k}+sum_{k+1,i}) dpi,j=min(dpi,j,dpi,k+sumk+1,i)

代码:

#include 
#include 
#include 
#include 
#include 
#include 

#define rep(i, st, ed) for (int i = st; i <= ed; i++)
#define rwp(i, ed, st) for (int i = ed; i >= st; i--)

#define inf 0x7fffffff 
#define N 1005

using namespace std;

int sum[N][N], dp[N][55], g[N][N], r[N], n, s, K, x;

int main()
{
    scanf("%d %d %d", &n, &s, &K);
    rep(i, 1, n)
    {
        scanf("%d", &r[i]);
        rep(j, 1, i - 1)
           if (r[i] > r[j]) sum[r[i]][r[j]]++;
    }
    memset(dp, 127, sizeof(dp));
    rep(i, 1, s)
        rep(j, 1, i) sum[i][j] += sum[i][j - 1];
    rep(i, 1, s)
        rep(j, i, s)
            g[i][j] = g[i][j - 1] + (sum[j][j] - sum[j][i - 1]);         
    dp[0][0] = 0;  
    rep(i, 1, s)
        rep(j, 1, K)
            rep(k, 0, i - 1)
                dp[i][j] = min(dp[i][j], dp[k][j - 1] + g[k + 1][i]);
    printf("%d\n", dp[s][K]);
}

你可能感兴趣的:(C++,动态规划)