在猴村有一條筆直的山路,這條山路很窄,寬度忽略不計。有 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]; }