在猴村有一条笔直的山路,这条山路很窄,宽度忽略不计。有 n只猴子正站在山路上静静地观望今天来参加比赛的各位同窗。用一个正整数Xi表示第i只猴子所站位置,任意两只猴子的所站位置互不相同。在这条山路的m个位置上种着一些高大的树木,正整数Yj表示第j棵树木所在的位置,任意两棵树的位置互不相同。ios
正当猴子们聚精会神的欣赏各位高超编程技能 聚精会神的欣赏各位高超编程技能时,一只老虎大摇摆的走了过来。猴子们吓得直冒冷汗,第一反应就是找棵大树爬上去这样能避免被老虎咬死或者吃掉(不考虑老虎上树问题)。编程
在位置a的猴子跑到在位置b的大树上,须要消耗能量为|a-b|(即 a-b的绝对值)。为了尽量有效利用这些大树避难,每棵上至少要一只猴子。 请编程计算n只猴子所有上树最少须要消耗多能量?数组
输入格式:优化
输入共4行。spa
第1行一个整数 n,表示猴子的数量。code
第2行n个整数,i个整数个整数Xi表示第i只猴子所在的位置。blog
第3行一个整数m,表示大树的数量。排序
第4行m个整数,第j个整数表示第j棵大树所在的位置。ci
输出格式:get
输出一行,一个整数表示n只猴子所有上树最少须要消耗的能量。
输入样例#1: 复制
3
1 4 5
2
3 8
输出样例#1: 复制
6
输入样例#2: 复制
3
3 1 10
2
8 3
输出样例#2: 复制
4
30%的数据,\(1≤n≤500,1≤X_i,Y_i≤10^5\)。
100%的数据,\(1≤n≤5000,1≤m≤n,1≤Xi_,Y_i≤10^9\)。
动态规划+滚动数组优化空间+排序。
先把猴子和树排序,这很容易想到,贪心确定不行,由于你没法肯定哪些树有猴子,并且保证全局最优,因而想到了DP。
咱们设\(f[i][j]\)表明前\(i\)只猴子占满了前\(j\)颗树,容易想到DP方程为
\[f[i][j]=min(f[i-1][j-1]+abs(x[i]-y[j]),f[i-1][j]+mn[i][j]);\]
\(mn[i][j]\)表明第\(i\)只猴子在上前\(j\)颗树的最小能量,能够预处理出来。
发现\(f[i][j]会爆\)\(int\),因此要开\(long~long\),数据范围5000?,好像
\(f[5000][5000]\)会爆,容易发现\(f[i][j]\)转移只和上一次有关,能够用滚动数组,因而转移方程为\[f[p][j]=min(f[p~xor~1][j-1]+abs(x[i]-y[j]),f[p~xor~1][j]+mn[i][j]);\]
代码以下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; ll f[2][5010],x[10010],y[10010]; int mn[5010][5010]; int sba(int x) { if(x<0) return -x; return x; } int main() { memset(f,0x3f,sizeof(f)); ll n,m; cin>>n; for(ll i=1;i<=n;i++) cin>>x[i]; sort(x+1,x+1+n); cin>>m; for(ll i=1;i<=m;i++) cin>>y[i]; sort(y+1,y+1+m); for(ll i=1;i<=n;i++) mn[i][0]=2e9; for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++) mn[i][j]=min(mn[i][j-1],sba(x[i]-y[j])); f[1][1]=sba(x[1]-y[1]); for(ll i=2;i<=n;i++) { ll qq=min(i,m); for(ll j=1;j<=qq;j++) { ll p=i%2; f[p][j]=min(f[p^1][j-1]+sba(x[i]-y[j]),f[p^1][j]+mn[i][j]); } } ll p=n%2; cout<<f[p][m]; }