您的位置:首页 > 其它

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

2017-03-29 19:22 211 查看

地震预测

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
.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;
}


总结:感觉真是很有意思的一道题,因为一般的想法的话肯定是一个一个找最小值,这种通过链表先排序后找的方法很巧妙啊。

以前也从来没有用过链表写过题,现在忽然发现链表很强大啊。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: