POJ3666
此題對我意義非凡,畢竟看別人的博客能看暈倒是沒誰了。
同樣是初始化的問題。
然後,是個Dp.重點在於怎麼確定最優是從原數列中選取的。由於兩個或是遞增或是遞減,可以在中間或者兩個端點取得。三個的話,1,5,2,假設如此,最優同樣是2和5之間,包括端點,都可以取,然後5到此點的距離和2到此點的距離要加和,保持一定,所以點可以在這個區間裏取,然後若是1,5,-1,同樣所求的改變的最小爲5和-1 之間的距離爲6,而1在裏面,顯然取>=1這個點,若是其他點的話,就要多了1到這個點的距離,再想一下極限,就是5,4 再是無窮多個1,也是取1,也就是說取的點是和數據有關,所以,只能確定所有變化後的點都是由原數列的數得來的。至於爲什麼呢?再有一組數據7,6,5,4,3,2,7其中765可以確定中間點6可取,(5~7可取),432確定3可取(2~4可取)。那麼由於6>5>4>3,無論怎麼取,取4.~5則多了3*(5-4),3~4等也是。所以綜上所有組情況由上組合,都是可以轉化爲數列的一個數。
同時這個模型屬於常識,我看網上的博客有點暈,加上有的博客還誤導人。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2003;
int a[maxn];
int b[maxn];
int dp[maxn][maxn];
int m=0;int n;int nm=1e9+2;
void solve()
{
for(int i=1;i<=n;i++)
{
nm=dp[i-1][1];//
for(int j=1;j<=n;j++)
{
nm=min(nm,dp[i-1][j]);
dp[i][j]=nm+abs(a[i]-b[j]);
}
}
int res=dp[n][1];
for(int i=1;i<=n;i++)
{
//if(dp[n][i])
res=min(res,dp[n][i]);
}
cout<<res<<endl;
}
int main()
{
//int n ;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+n+1);
solve();
return 0;
}