牛吃药

牛吃药

半个月之前Alice买了一些竹竿,拼接之后Alice把它截成等长的四段,围出一个正方形的牛棚用来养牛。由于Alice的畜牧经验不足,这头牛患了病。Alice找到当地的兽医开药,并药物拌入饲料喂给这头牛。

假设这个牛棚是个边长为N的正方形,牛棚中所有的点描述为从(0,0)到(N,N)的坐标,牛棚的边缘的各点都堆有饲料,而其中只有M个点放置的是拌有药品的饲料。

假设牛在吃完一堆饲料再吃下一堆时,只会选择与刚吃完这堆相邻近的饲料。现在这头牛需要吃K堆含药饲料才能痊愈,吃每堆饲料要花1分钟。
若从吃完第一堆开始计时,请问这头牛最少要额外花几分钟才能达到吃药的目标

数据输入

第一行有三个整数N,M,K

接下来有M行,每行两个整数表示拌入药物的饲料的坐标,题目保证给出的坐标在正方形的边缘

1 ≤ N,M ≤105
1 ≤K ≤ M
0 ≤ xi,yi≤N
xi与yi至少有一个为0或为N(保证坐标在正方形牛棚的边缘)

数据输出

输出一行,一个整数,代表牛吃到相应数量的药最短可能花费的时间

样例1
输入样例

5 5 3
5 3
0 0
0 4
3 0
1 5

输出样例

6

提示

输入样例的解如下图示,牛从E开始吃第一堆。吃完E点的第一堆开始计时,第1分钟在点(0,5)吃,第2分钟在点(0,4)吃,…直到第6分钟吃完(0,0)的饲料,吃了3次药达到目标,花费6分钟。当然,如果牛先从B开始然后顺时针吃C和E也可以,同样花费6分钟

思路

固定一个方向比如逆时针。枚举M个点,对每个点计算到逆时针接下来k个药的最短距离,枚举一遍后输出其最小值即可。如果将各坐标按四条边排序,就将二维转换成一维。

代码

#include<bits/stdc++.h>
using namespace std;
//using std::abs;//这一行是? 
struct plugs
{
    int x,y;
    int distToNext;
    int distToOrigin;
    bool operator<(const plugs &b) const//这一行是运算符重载,定义比较方法 
    {
        return distToOrigin<b.distToOrigin;//按照规定的逆时针序号排序, <就是这个序号小于 
    }
};

int main(void)
{
    //std::vector<plugs> s;
    vector<plugs> s;
    int i,x,y,N,M,K;
    plugs *p;
    p=(plugs*)malloc(sizeof(plugs));//定义指针,开辟空间 
    scanf("%d%d%d",&N,&M,&K);

    for(i=0;i<M;i++)
    {
        scanf("%d%d",&x,&y);
        p->x=x;
        p->y=y;
        p->distToNext=0;
        if (y==0 && 0<=x && x<N)//在下底边上 
            p->distToOrigin=x;//这里是开始一维编号,逆时针开始依顺序编号 
        else if ( x==N && 0<y && y<=N)//在右边 
            p->distToOrigin=N+y;
        else if ( y==N && 0<x && x<=N)//在上顶边 
            p->distToOrigin=3*N-x;
        else
            p->distToOrigin=4*N-y;
        s.push_back(*p);
    }//成功一维化,类似循环队列。 

    //std::sort(s.begin(),s.end());
    sort(s.begin(),s.end());//默认是升序排列,这里必须先排序才行 
    p->distToOrigin=s[0].distToOrigin+4*N;//这是减法借位 
    s.push_back(*p);//此处是特殊处理 

    for(i=0;i<M;i++)
        s[i].distToNext=s[i+1].distToOrigin-s[i].distToOrigin;//记录要前进的步数 
    //一维化彻底完成 
    int tmpSum=0,minVal=0x7FFFFFFF;//设置一个哨兵 
    K--;
    for(i=0;i<K;i++)
    {
        tmpSum+=s[i].distToNext;//排除起点记录,吃到k个含药的,要花的时间 
    }//此处是从s[0]开始吃药 
    for(i=0;i<M;i++)//开始枚举 
    {
        tmpSum=tmpSum+s[(i+K)%M].distToNext-s[i].distToNext;//核心 
        if(tmpSum<minVal)
            minVal=tmpSum;
    }
    printf("%d\n",minVal);
    delete p;
    return 0;
}

-s[i].distToNext;先去除此次的起点,
s[(i+K)%M].distToNext是此次的终点,更新一波,这样可以实现枚举。

posted @ 2019-03-13 15:05  lingr7  阅读(127)  评论(0编辑  收藏  举报