• P1103 书本整理 题解


    CSDN同步

    原题链接

    简要题意:

    给定 (n) 个二元组 ({x,y}),你的任务首先要将它们按照 (x) 排序(保证 (x) 两两不同),然后从中去掉 (k) 个二元组,使得 剩下的每相邻二元组 (y) 的差的绝对值之和最小,求这个最小值。

    (n leq 100 , x,y leq 200).

    原题中书的高度即为 (x),书的宽度即为 (y).

    首先我们建立结构体 ( ext{book {height , width}}) 来存储每一本书的情况,便于排序操作。其次我们考虑,类似 (n space ext{choose} space k) 的做法,数据范围很弱,考虑用 动态规划 做。

    考虑反其道而行之,去掉 (k) 个也就是反选 (n-k) 个,换成了熟悉的形式。用 (f_{i,j}) 表示前 (i) 本书选 (j) 本(必须选第 (i) 本)的最优答案。

    这样很容易得到:

    [f_{i,l} = egin{cases} 0 space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space space , l = 1 \ min_{j=1}^i f_{j,l-1} + |a_i . ext{width} - a_j . ext{width}| , l > 1\ end{cases}]

    第一行是边界条件,很显然选 (1) 个肯定是 (0). 其余情况枚举从那里开始选就可以了。

    时间复杂度:(mathcal{O}(n^3)).

    实际得分:(100pts).

    // 其实不用开 long long , 特此注明
    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N=1e2+1; 
    
    inline int read(){char ch=getchar(); int f=1; while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;}
    
    inline void write(int x) {
    	if(x<0) {putchar('-');write(-x);return;}
    	if(x<10) {putchar(char(x%10+'0'));return;}
    	write(x/10);putchar(char(x%10+'0'));
    }
    
    struct book {
    	int height,width;
    } a[N]; int n,k; 
    ll f[N][N];
    
    inline bool cmp(book x,book y) {
    	return x.height<y.height;
    }
    
    int main() {
    	n=read(),k=read();
    	for(int i=1;i<=n;i++) a[i].height=read(),a[i].width=read();
    	sort(a+1,a+1+n,cmp);
    	memset(f,127,sizeof(f));
    	for(int i=0;i<=n;i++) f[i][1]=0ll; //初始化极大值和边界
    	for(int i=2;i<=n;i++) for(int j=1;j<i;j++)
    	for(int l=2;l<=min(i,n-k);l++)
    		f[i][l]=min(f[i][l],f[j][l-1]+abs(a[i].width-a[j].width)); //转移操作
    	ll ans=(1ll<<62);
    	for(int i=n-k;i<=n;i++) ans=min(ans,f[i][n-k]); //统计答案
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    
    
  • 相关阅读:
    整理前端面试题1
    前端面试题2
    6.显示锁Lock 和 线程通信Condition
    5.创建执行线程的方式之三 :实现Callable 接口
    4.闭锁 CountDownLatch
    3.ConcurrentHashMap 锁分段机制 Copy-On-Write
    2.原子变量 CAS算法
    1.volatile关键字 内存可见性
    13.MyBatis注解式开发
    12.查询缓存
  • 原文地址:https://www.cnblogs.com/bifanwen/p/13669678.html
Copyright © 2020-2023  润新知