FZU 1492 地震预测(模拟链表)(技巧题)

115 篇文章 0 订阅
3 篇文章 0 订阅

地震预测

Problem Description

怀特先生是一名研究地震的科学家,最近他发现如果知道某一段时间内的地壳震动能量采样的最小波动值之和,可以有效地预测大地震的发生。

假设已知一段时间的n次地壳震动能量的采样值为a1,a2,…an,那么第i 次采样的最小波动值为min{|ai-aj| | i<j<=n},即第i 次采样的最小波动值是其后n-i次采样值与第i次采样值之差的绝对值中最小的值,特别地,第n次采样的最小波动值为an。

请编写一个程序计算这n次采样的最小波动值之和。

Input

本题有多组输入数据,你必须处理到EOF为止

输入数据第一行有一个数n(1<=n<=105) ,表示采样的次数。

第二行有n个整数,表示n次地壳震动能量的采样值a1,a2,…an (0<=ai<=107 )。

Output

输出n次采样的最小波动值之和。

Sample Input

4
2 0 3 10
Sample Output

21

ps:题意很容易懂,就是一般的方法直接就TLE了。。。
分析:
题目要求的是每一个数与它后面的数的最小差值之和,所以我们可以先把给定的数字从小到大排序(要先记录下每一个数原先的位置);

因为有序,所以最小差值肯定是减去左边或者右边的值,但是如果是单纯的数组的话,它的左边或右边不一定是它原顺序后面的数,

因此我们可以数组模拟链表(记录下排序后每一个数的位置),从原顺序的第一个数开始计算,计算完后就将这个数字从链表中删除,并更新链表中它的前一位的next和后一位的pre,具体详见代码

代码:

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;

#define maxn 100000+10
#define min(a,b) (a<b?a:b)
const int inf=2000000000;
struct node
{
    int x,po;
}num[maxn];
int pre[maxn],next[maxn],c[maxn],list[maxn];
int n;

bool cmp(node a,node b)
{
    return a.x<b.x;
}

int Find(int i)
{
    int x1=-inf,x2=inf;
    if(pre[i]>=1)
        x1=list[pre[i]];
    if(next[i]<=n)
        x2=list[next[i]];
    return min(abs(list[i]-x1),abs(list[i]-x2));
}

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i].x);
            num[i].po=i;
        }
        int ed=num[n].x;
        sort(num+1,num+n+1,cmp);
        for(int i=1;i<=n;i++)
        {
            list[i]=num[i].x;
            c[num[i].po]=i;
            pre[i]=i-1;
            next[i]=i+1;
        }
        int ans=0;
        for(int i=1;i<n;i++)
        {
            ans+=Find(c[i]);
            pre[next[c[i]]]=pre[c[i]];//更新链表
            next[pre[c[i]]]=next[c[i]];//
        }
        printf("%d\n",ans+ed);
    }
    return 0;
}



总结:感觉真是很有意思的一道题,因为一般的想法的话肯定是一个一个找最小值,这种通过链表先排序后找的方法很巧妙啊。
以前也从来没有用过链表写过题,现在忽然发现链表很强大啊。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值