题目:http://acm.fzu.edu.cn/problem.php?pid=1492
思路:思路1 超时,思路2 改进AC。
思路1(简单,超时):
步骤:1.将能量排序,存入数组a[max] 2.按输入顺序,依次在有序数组中找ai。3.ai的最小波动值,要么是 (ai的后一个值) - ai ,要么是 ai - (ai前一个值)4.将排序好的数组删除ai(将数组后面的元素覆盖前面的)(剩下的均是ai后来的能量)5.重复2、3、4步,直到a[i]删除完。
代码:
1 #include<stdio.h> 2 #include<algorithm> 3 using namespace std; 4 int main() 5 { 6 int j,n,m,bi,b1,b2,sum,k,c,g,a[100005],b[100005];//b记录原数据,a用来处理 7 //输入 8 while(~scanf("%d",&n)) 9 { 10 m=n;//m是数组长度,不变,n用来改变 11 sum=0;//初始化 12 for(j=0; j<n; j++) 13 { 14 scanf("%d",&a[j]); 15 b[j]=a[j]; 16 } 17 sort(a,a+n); 18 for(j=0; j<m; j++) 19 { 20 //找aj 21 for(k=0; k<n; k++) 22 { 23 if(a[k]==b[j]) 24 { 25 if(k==n-1) //找到的这个数在数组末尾 26 { 27 bi=b[j]-a[k-1]; 28 } 29 else if(k==0) //找到的这个数在数组首位 30 { 31 bi=a[k+1]-b[j]; 32 } 33 else //找到的这个数在中间 34 { 35 b1=a[k+1]-b[j]; 36 b2=b[j]-a[k-1]; 37 bi=(b1>b2)?b2:b1;//取两个里面的小的 38 } 39 sum=sum+bi; 40 //删除它(后面的往前挪,数组长度 减1) 41 for(c=k; c<n-1; c++) //从前往后 42 { 43 a[c]=a[c+1]; 44 } 45 n--; 46 break; 47 } 48 } 49 } 50 printf("%d\n",sum); 51 } 52 return 0; 53 }
思路2:
上一个思路超时了,每一次都要从头到尾寻找ai,时间复杂度又乘了一个n。优化时,用数组b[max]记录原输入在有序数组中的位置,这样第i个输入的数就是a[b[i]],如何确定数组b[max]?
排序后,为了不进行 删除 操作,将每一个数左右两边的数记录(记录下标方便一些),最小波动值在这里产生,不删除的话,左右两边的数一定要及时更新。
例如:2 0 3 10 排序后为0 2 3 10,首先找2的最小波动值,2的左右两边分别为0,3,则波动值为min{2-0,3-2}=1,接下来就要更新了,0的右边 由2变成3,3的左边 由2变成0。像极了链表的形式,其实这个操作就相当于删去了2。
代码:
1 #include<stdio.h> 2 #include<algorithm> 3 #define max 100000000 4 using namespace std; 5 struct node 6 { 7 int ai,i,left,right;//ai——能量,i-录入的顺序,left-排序后此数左边的数(下标),right--排序后次数右边的数(下标) 8 } a[100005]; 9 int b[100005];//储存原数组在有序数组中的位置(不用遍历寻找) 10 bool cmp(node a1,node a2) 11 { 12 return a1.ai<a2.ai; 13 } 14 int main() 15 { 16 int n,m,j,c,sum,bi,b1,b2; 17 while(~scanf("%d",&n)) 18 { 19 sum=0; 20 for(j=1; j<=n; j++) 21 { 22 scanf("%d",&a[j].ai); 23 a[j].i=j; 24 } 25 sort(a+1,a+n+1,cmp); 26 //确定b[max] 27 for(j=1; j<=n; j++) 28 { 29 b[a[j].i]=j;//原数组在有序数组a[i]中的位置 30 } 31 //确定左右的数 在数组a[max]中 的下标 32 for(j=1; j<=n; j++) 33 { 34 a[j].left=j-1; 35 a[j].right=j+1; 36 } 37 a[0].ai=max*(-1); 38 a[n+1].ai=max; 39 //确定最小波动值 40 for(j=1; j<n; j++) 41 { 42 if(b[j]==n) //这个数在数组末尾 43 { 44 //计算最小波动值 45 bi=a[b[j]].ai-a[a[b[j]].left].ai;//这个数-左边的数 46 //更新 47 a[a[b[j]].left].right=a[b[j]].right;//此数的左边的数 的右边 变成 这个数的右边 48 } 49 else if(b[j]==1) //这个数在数组首位 50 { 51 bi=a[a[b[j]].right].ai-a[b[j]].ai;//右边的数-这个数 52 a[a[b[j]].right].left=a[b[j]].left;//此数的右边的数 的左边 变成 这个数的左边 53 } 54 else //这个数数组在中间 55 { 56 b1=a[b[j]].ai-a[a[b[j]].left].ai;//这个数-左边的数 57 b2=a[a[b[j]].right].ai-a[b[j]].ai;//右边的数-这个数 58 bi=b1>b2?b2:b1; 59 a[a[b[j]].left].right=a[b[j]].right;//此数的左边的数 的右边 变成 这个数的右边 60 a[a[b[j]].right].left=a[b[j]].left;//此数的右边的数 的左边 变成 这个数的左边 61 } 62 sum=sum+bi; 63 } 64 sum=sum+a[b[n]].ai;//加上最后一个数 65 if(n==0) 66 sum=0; 67 printf("%d\n",sum); 68 } 69 return 0; 70 }