题解 P1103 【书本整理】

一道很好的DP入门题,~~适合像我这种学了大半年却还不会DP的人。~~

首先,题目要求我们将书本按照高度排序,在这里我们可以用结构体实现。

其次才是重点,推DP方程。

题目中说抽走K本书,我们不妨转换一下:

从n本书中留下(n - k)本。

然后,寻找每本书之间的关系:

对于第一本书,如果留下,花费显然只能是0。


对于第二本书,如果留下:

1、可以选择将自己作为开头,或者与前面的书连在一起。

2、当然,我们也可以不留下。

对于第三本书,如果留下:

1、自己作为开头
2、与第一本书连接或者与第二本书连接
3、不留下

那么,我们想办法将每本书的与前面的书形成联系:

设置$f_{i,j}$表示第$i$本书,与前面的书连接形成长为$j$的连接。

那么,有:

$f_{i,i}$ = 0

$f_{i,j}$ = min($f_{i,j}$, $f_{i,x-1}$ + $abs$($w_i$ - $w_x$) 其中$x$指与前面连接的书的编号。

那么,废话不多说,上代码:

#include <bits/stdc++.h>
using namespace std;
#define N 1010

inline int read(){
    int x = 0, s = 1;
    char c = getchar();
    while(!isdigit(c)){
        if(c == '-')s = -1;
        c = getchar();
    }
    while(isdigit(c)){
        x = x * 10 + (c ^ '0');
        c = getchar();
    }
    return x * s;
} 

int f[N][N];

struct node{
    int h, w;
} t[N];

bool cmp(node a, node b){
    return a.h < b.h;
}

int main(){
    int n = read(), k = read();
    for(int i = 1; i <= n; i++){
        t[i].h = read(), t[i].w = read();
    }
    sort(t + 1, t + n + 1, cmp);
    memset(f, 127, sizeof(f));
    for(int i = 1;i <= n; i++){
        f[i][1] = 0;  //只选自己时的费用为0
    }
    for(int i = 2;i <= n; i++){ //试着放第 i 本 
        for(int j = 1;j <= i - 1; j++){  /*从哪一本开始连接*/
            for(int l = 2;l <= min(i, n - k); l++){ /*继承多长*/
                f[i][l] = min(f[i][l], f[j][l - 1] + abs(t[i].w - t[j].w));
            }
        } 
    }
    int ans = (int)9e9;
    for(int i = 1; i <= n; i++)
        ans = min(ans, f[i][n - k]);
    printf("%d
", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/wondering-world/p/13278796.html