FOJ1492——地震预测

题目: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 }

 

转载于:https://www.cnblogs.com/li-yaoyao/p/9486361.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值