2017-05-29
题目大意:
输入的第一行为一个数N(1<=N<=1000),接下来的N行每行有一个介于0~100之间的整数。需要保证这些整数中最大和最小的值相差不大于17。可以改变每个值仅一次(改变的大小为一个整数值),且改变一个值需花费的代价为所做改变的大小的平方。输出为所需代价的最小值。
样例输入:
5
20
4
1
24
21
样例输出:
18
题解:
首先将输入的N个数从小到大排序。如果N=1,则代价为0;如果N=2,则代价为输入的两个整数的差拆分为最接近的两部分后的平方和。如果N>2,由题意得出,要用最小的代价实现让所有的数分布在一个大小为17的区间以内,所以:
(1)其中最小和最大的数相差不大于17,那么代价为0; (2)设置一个大小为17的区间,设这个区间的下界为low,上界为high。则初始时low为最小的那个数,high为low+17。计算所有小于low的数改变成low所需的代价与所有大于high的数改变成high所需的代价之和,记为cost。移动这个区间,直到high等于最大的那个数。其中,最小代价为区间移动过程中cost的最小值。
代码如下:
/*
ID: madara01
PROG: skidesign
LANG: C++
*/
#include <iostream>
#include <fstream>
#include <string>
#define cin fin
#define cout fout
#define MAX 1001
using namespace std;
int n;
int hills[MAX];
//心累-_-,又编译错误。。自己写个排序吧...
void sort() {
int gap, i, j, temp;
for(gap = n/2; gap > 0; gap /= 2)
for(i = gap; i < n; i++)
for(j=i-gap; j>=0 && hills[j]>hills[j+gap]; j-=gap) {
temp = hills[j];
hills[j] = hills[j+gap];
hills[j+gap] = temp;
}
}
int main(int argc, char **argv)
{
int i,cost = 1000000,temp1,temp2;
ofstream fout ("skidesign.out");
ifstream fin ("skidesign.in");
cin >> n;
for(i = 0; i < n; i++) cin >> hills[i];
sort();
if(hills[n-1] - hills[0] <= 17) cost = 0; //值都在一个大小为17的区间内
else if(n == 1) cost = 0; // 只有一座山
else if(n == 2) //只有两座山
{
temp1 = (hills[1] - hills[0]) / 2;
temp2 = (hills[1] - hills[0])-temp1;
cost = temp1*temp1 + temp2*temp2;
}
else{
temp1 = hills[0]; temp2 = temp1 + 17; //temp1,temp2指示一个差为17的高度区间
int temp = 0;
int low,high; //low,high表示山的编号
while(temp2 <= hills[n-1]) {
low = 0; high = n-1;
while(hills[low] < temp1) {
temp = temp + (temp1 - hills[low])*(temp1 - hills[low]);
low ++;
}
while(hills[high] > temp2){
temp = temp + (hills[high] - temp2)*(hills[high] - temp2);
high --;
}
temp1++; temp2++;
if(temp < cost) cost = temp;
temp = 0;
}
}
cout << cost << endl;
return 0;
}