牛吃药
半个月之前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
",minVal);
delete p;
return 0;
}
-s[i].distToNext;
先去除此次的起点,
s[(i+K)%M].distToNext
是此次的终点,更新一波,这样可以实现枚举。