USACO-Section 1.3 Ski Course Design Lock[...]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值