POJ3666
题目链接:http://poj.org/problem?id=3666
题目大意:
有一个由 N 个数组成的数组num,要求通过加减其中元素的数字把它变成一个不减数列或者不增数列。让一个数字加 1 的花费为 1,求最小花费。
AC思路:
DP题。拿着个假算法搞了半天然后明智地放弃了。思路来源于网上。
我们先来讨论如何用最小花费让数列变成不减数列。
dp[i][j] 表示对于前 i 个元素,最大数(也可以理解为是最后一个数)是 j 时的最小花费。则 dp[i][j] = abs(num[i]-j) + min(dp[i-1][k], 0<=k<j).
Warning! 数据类型要用 long long 否则 WA!
要离散化。
AC代码:
1 #include <iostream> 2 #include <algorithm> 3 #include <cmath> 4 #include <cstdio> 5 #include <map> 6 using namespace std; 7 typedef long long ll; 8 const int maxn=2000+5; 9 const ll inf=0x7fffffff; 10 map<ll,int> lists; 11 ll A[maxn],As[maxn]; 12 ll dp[maxn][maxn]; 13 ll abss(ll a,ll b){ 14 if(a>b) return a-b; 15 return b-a; 16 } 17 int main(){ 18 int N; 19 scanf("%d",&N); 20 int num=0; 21 for(int i=0;i<N;i++){ 22 scanf("%d",&A[i]); 23 if(lists[A[i]]==0){ 24 lists[A[i]]=1; 25 As[num++]=A[i]; 26 } 27 } 28 sort(As,As+num); 29 for(int i=0;i<num;i++) 30 lists[As[i]]=i; 31 for(int i=0;i<num;i++) 32 for(int j=0;j<N;j++) 33 dp[i][j]=inf; 34 ll ans=inf; 35 for(int i=0;i<N;i++){ 36 ll mm; 37 if(i==0) mm=0; 38 else mm=dp[i-1][0]; 39 for(int j=0;j<num;j++){ 40 if(i!=0) mm=min(mm,dp[i-1][j]); 41 dp[i][j]=abss(As[j],A[i])+mm; 42 if(i==N-1) ans=min(ans,dp[i][j]); 43 } 44 } 45 printf("%lld\n",ans); 46 return 0; 47 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”