编程题12 - 疯狂队列(网易)

题目描述

小易老师是非常严厉的,它会要求所有学生在进入教室前都排成一列,并且他要求学生按照身高不递减的顺序排列。有一次,n个学生在列队的时候,小易老师正好去卫生间了。学生们终于有机会反击了,于是学生们决定来一次疯狂的队列,他们定义一个队列的疯狂值为每对相邻排列学生身高差的绝对值总和。由于按照身高顺序排列的队列的疯狂值是最小的,他们当然决定按照疯狂值最大的顺序来进行列队。现在给出n个学生的身高,请计算出这些学生列队的最大可能的疯狂值。小易老师回来一定会气得半死。

输入描述:

输入包括两行,第一行一个整数n(1 ≤ n ≤ 50),表示学生的人数
第二行为n个整数h[i](1 ≤ h[i] ≤ 1000),表示每个学生的身高

输出描述:

输出一个整数,表示n个学生列队可以获得的最大的疯狂值。

如样例所示: 
当队列排列顺序是: 25-10-40-5-25, 身高差绝对值的总和为15+30+35+20=100。
这是最大的疯狂值了。

示例1

输入

5
5 10 25 40 25

输出

100

思路
假设数列是1,2,3,4,5,6,7。我们先取最小的元素1,要绝对值尽可能的大,第二个元素我们取最大值7,这样我们得到了[1,7], 
接下来,我们从剩下的元素中取最大值,排放在1的旁边,取最小值排放在7的旁边,这样我们得到了[6,1,7,2] 
继续上述过程,从剩下的元素中取最大值放在两侧较小元素的旁边,取最小值放在较大元素的旁边 
…… 
直到最后,我们每次取2个元素,剩余的元素个数可能为0,也可能为1.如果还剩下1个元素,比较一下放在左边和右边的差值绝对值,那边大放哪边就好。
 

建立一个双向链表保存数据

/*
7
1 2 3 4 5 6 7
*/
#include <stdio.h>
#include <string.h>

int find_max(int * arr,int num)
{
	int i, count = 0, temp = 0;
	for (i = 0; i < num; i++)
	{
		if (arr[i]>temp)
		{
			temp = arr[i];
			count = i;
		}
	}
	arr[count] = 0;
	return temp;
}

int find_min(int * arr, int num)
{
	int i, count = 0, temp = 0x7fffffff;
	for (i = 0; i < num; i++)
	{
		if (arr[i]!=0 && arr[i]<temp)
		{
			temp = arr[i];
			count = i;
		}
	}
	arr[count] = 0;
	return temp;
}

typedef struct list_ {
	int data;
	struct list_* prev;
	struct list_* next;
}list;

list* creat_node(void)
{
	list* node;
	node = (list*)malloc(sizeof(list));
	node->data = 0;
	node->prev = NULL;
	node->next = NULL;
	return node;
}

int main(void)
{
	int i = 0, j = 0, k = 0, num = 0, err = 0;
	list *a, *b, *c, *d, *ak, *ah, *bk, *bh;
//	int *heights;
	int heights[100] = { 0 };
	scanf("%d",&num);
//	heights = (int *)malloc(num);
	for (i=0;i<num;i++)
	{
		scanf("%d", &heights[i]);
	}


	if (num == 1)
	{
		printf("0");
	}
	else if (num == 2)
	{
		printf("%d", abs(heights[0] - heights[1]));
	}
	else
	{
		int ai = 0;
		int var = 0;;
		ai = (num - 2) / 2;
		a = creat_node();
		b = creat_node();
		a->data = find_min(heights, num);
		b->data = find_max(heights, num);
		a->next = b;
		b->prev = a;
		for (j = 0; j < ai; j++)
		{
			c = creat_node();
			d = creat_node();
			c->data = find_max(heights, num);
			d->data = find_min(heights, num);
			if (j % 2 == 0)
			{
				a->prev = c;
				c->next = a;
				b->next = d;
				d->prev = b;
				a = c;
				b = d;
			}
			else
			{
				a->prev = d;
				d->next = a;
				b->next = c;
				c->prev = b;
				a = d;
				b = c;
			}
		}
		ak = a;
		for (;;)
		{
			if (ak->prev != NULL)
			{
				ak = ak->prev;
			}
			else
			{
				break;
			}
		}
		ah = b;
		for (;;)
		{
			if (ah->next != NULL)
			{
				ah = ah->next;
			}
			else
			{
				break;
			}
		}
		if (num % 2 == 1)
		{
			var = find_max(heights, num);
			if (abs(var - ak->data) > abs(var - ah->data))
			{
				bk = creat_node();
				bk->data = var;
				ak->prev = bk;
				bk->next = ak;
				ak = bk;
			}
			else
			{
				bh = creat_node();
				bh->data = var;
				ah->next = bh;
				bh->prev = ah;
				ah = bh;
			}
		}
		for (;;)
		{
			if (ak->next != NULL)
			{
				err += abs(ak->data - ak->next->data);
				ak = ak->next;
			}
			else break;
		}
	}
	printf("%d",err);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值