1. 程式人生 > 其它 >書本整理

書本整理

今日一題,我以為又是區間dp,結果寫出六重迴圈,又想一想這不是隻列舉一個端點就行嗎。

先看題:

洛谷P1103 書本整理

題目描述

Frank是一個非常喜愛整潔的人。他有一大堆書和一個書架,想要把書放在書架上。書架可以放下所有的書,所以Frank首先將書按高度順序排列在書架上。但是Frank發現,由於很多書的寬度不同,所以書看起來還是非常不整齊。於是他決定從中拿掉k本書,使得書架可以看起來整齊一點。

書架的不整齊度是這樣定義的:每兩本書寬度的差的絕對值的和。例如有4本書:

1×2
5×3
2×4
3×1
那麼Frank將其排列整齊後是:

1×2
2×4
3×1
5×3
不整齊度就是2+3+2=7

已知每本書的高度都不一樣,請你求出去掉k本書後的最小的不整齊度。

輸入格式

第一行兩個數字n和k,代表書有幾本,從中去掉幾本。(1n100,1k<n)

下面的n行,每行兩個數字表示一本書的高度和寬度,均小於200。

保證高度不重複

輸出格式

一行一個整數,表示書架的最小不整齊度。

輸入輸出樣例

輸入 #1 4 1 1 2 2 4 3 1 5 3 輸出 #1 3

首先,可以固定左端點在陣列的最左端,然後從左到右列舉右端點(保證此時的右端點一定不會去掉),再列舉從左端點到右端點中去掉書的本數,這裡就會出現一個問題——右端點前面的那本書(就是右端點前面沒有被刪掉的最接近右端點的那本書)是哪本?為了解決這個問題,就需要再列舉那本書是哪本就可以了。最後如果右端點前沒有書,就記0。

下面是程式碼:

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int n,k;
struct node{
    int h,w;
}a[110];
int f[110][110];
int cmp(node x,node y){
    return x.h<y.h;
}
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i].h>>a[i].w;
    }
    
for(int i=1;i<=n;i++){ f[i][i]=0; } sort(a+1,a+n+1,cmp); a[0].w=a[1].w; for(int i=1;i<=n;i++){ for(int j=0;j<=k&&j<i;j++){ f[i][j]=f[i-1][j]+abs(a[i].w-a[i-1].w); for(int l=1;l<j;l++){ f[i][j]=min(f[i][j],f[i-1-l][j-l]+abs(a[i].w-a[i-1-l].w)); } if(i-1-j==0){ f[i][j]=0; } else{ f[i][j]=min(f[i][j],f[i-1-j][0]+abs(a[i].w-a[i-1-j].w)); } } } int minn=f[n-k+1][1]; for(int i=n-k+2;i<=n;i++){ minn=min(minn,f[i][i+k-n]); } cout<<minn; return 0; }