10403: D.山區修路
Time Limit: 2 Sec Memory Limit: 128 MB Submit: 69 Solved: 23 [Submit][Status][Web Board]
Description
某山區的孩子們上學必須經過一條凹凸不平的土路,每當下雨天,孩子們非常艱難。現在村裡走出來的Dr. Kong決定募捐資金重新修建著條路。由於資金有限,為了降低成本,對修好後的路面高度只能做到單調上升或單調下降。
為了便於修路,我們將整個土路分成了N段,每段路面的高度分別A1,A2,….,An。由於將每一段路墊高或挖低一個單位的花費成本相同,修路的總費用與路面的高低成正比。
現在Dr. Kong希望找到一個恰好含N個元素的不上升或不下降序列B1,B2,….,Bn,作為修過的路路段的高度。要求:
| A1-B1| + | A2–B2| + ... + | An-Bn|------>最小
Input
第一行: K 表示有多少組測試資料。
接下來對每組測試資料:
第1行: N 表示整個土路分成了N段
第2~N+1行: A1 A2 ……AN 表示每段路面的高度
2≤k≤10 0≤Ai≤107 0≤N≤500 (i=1,…, N)
所有資料都是整數。 資料之間有一個空格。
資料保證| A1-B1|+| A2-B2|+ ... +| An-Bn|的最小值不會超過109
Output
對於每組測試資料,輸出佔一行:| A1-B1|+| A2-B2|+ ... +| An-Bn|的最小值。
Sample Input
2
7
1 3 2 4 5 3 9
5
8 6 5 6 2
Sample Output
3
1
HINT
Source
題解:把一串序列變為一段連續不增,或者連續不減的最小花費;
dp思想;dp[i][j]代表第i個元素換為第j個值的最小花費;
可列出狀態轉移方程:dp[i][j]=abs(m[i]-n[j])+mn;mn為轉化為1~j間的最小花費;
由於是單調遞增或者單調遞減,只需要升序降序下n陣列就可以了,對了,n陣列是離散化後的陣列;單增或者單減;
程式碼:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define mem(x,y) memset(x,y,sizeof(x))
#define SI(x) scanf("%d",&x)
#define SL(x) scanf("%lld",&x)
#define PI(x) printf("%d",x)
#define PL(x) printf("%lld",x)
#define P_ printf(" ")
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
typedef long long LL;
const int MAXN=510;
int m[MAXN],n[MAXN];
int dp[MAXN][MAXN];
int N;
int cmp(int a,int b){
return a>b;
}
int solve(){
int mn;
for(int j=1;j<=N;j++)dp[1][j]=abs(m[1]-n[j]);
for(int i=2;i<=N;i++){
mn=INF;
for(int j=1;j<=N;j++){
mn=min(mn,dp[i-1][j]);
dp[i][j]=abs(m[i]-n[j])+mn;
}
}
int ans=INF;
for(int i=1;i<=N;i++){
ans=min(ans,dp[N][i]);
}
return ans;
}
int main(){
int T;
SI(T);
while(T--){
SI(N);
for(int i=1;i<=N;i++)SI(m[i]),n[i]=m[i];
int ans1,ans2;
sort(n+1,n+N+1);
ans1=solve();
sort(n+1,n+N+1,cmp);
ans2=solve();
printf("%d\n",min(ans1,ans2));
}
return 0;
}
有大神用左偏樹,劃分樹寫的。。。。
連結:http://blog.163.com/hacker_james/blog/static/659024432011711105241183/
人家的思路: