Problem Description
度度熊在玩一个好玩的游戏。 游戏的主人公站在一根数轴上,他可以在数轴上任意移动,对于每次移动,他可以选择往左或往右走一格或两格。 现在他要依次完成 n 个任务,对于任务 i,只要他处于区间 [ai,bi]上,就算完成了任务。 度度熊想知道,为了完成所有的任务,最少需要移动多少次? 度度熊可以任意选择初始位置。
Input
第一行一个整数 T (1≤T≤10)表示数据组数。 对于每组数据,第一行一个整数 n (1≤n≤1000) 表示任务数。 接下来 nnn 行,第 iii 行两个整数 ai,bi (1≤ai≤bi≤1000000)表示任务对应的区间。
Output
对于每组数据,一行一个整数表示答案。
Sample Input
1
2
1 10
20 30
Sample Output
5
样例描述
选取10为起点,经过的轨迹为10-12-14-16-18-20。
题解思路:
(1)首先应当注意到题目中“依次完成”这四个大字!
(2)既然前提是依次完成,且还需要最短移动次数,那我们找出给出的区间之间的交集
(3)通过不断的合并前后的区间可以得到最后的互不相交的各个区间
(4)初始位置的选择需要考虑第一个区间和第二个区间的关系(这里的区间都是合并后的区间),如果第一个区间在第二个区间的左侧,那么初始点就选择第一个区间的右端点,反之选择左端点。
(5)确定了起点之后便是依次完成任务的循环,循环次数应当为区间数减一(最后一个区间单独计算)
(6)同样每次移动之前要判断当前位置和目标区间的位置关系,这样便可找出区间和当前位置的最短距离
(7)找到最短距离之后要判断是奇数还是偶数,如果距离是偶数,那就两步两步走到端点位置即可
(8)如果距离是奇数,开始判断:[1]目标区间是否为单值;[2]当前位置是否在目标区间与下一个目标区间之间。如果满足这两个条件其中一个,那我们移动后的落点就应当在目标区间的端点上
(9)如果(8)的条件一个不满足,那我们就可以用两步两步走到目标区间之内,然后继续下一次循环
(10)当结束循环后直接计算当前位置和最后一个区间的距离即可。
AC代码如下:
#include<iostream>
#include<vector>
using namespace std;
typedef struct
{
int star;
int end;
} Point;
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
Point t;
t.star = 0;
t.end = 1000005;
vector<Point>T;
int a,b;
for(int i=0; i<n; i++)
{
cin>>a>>b;
if(a<=t.end&&b>=t.star)
{
t.star = t.star>a?t.star:a;
t.end = t.end<b?t.end:b;
}
else
{
T.push_back(t);
t.star = a;
t.end = b;
}
}
T.push_back(t);
int sum=0,S;
if(T.size()>1)
{
S = T[0].star<T[1].star?T[0].end:T[0].star;
for(int j=1; j<T.size()-1; j++)
{
if(S>T[j].star)
{
if((S-T[j].end)%2==0)
{
sum += (S-T[j].end)/2;
S = T[j].end;
}
else
{
if((T[j].star<T[j+1].star)||(T[j].star==T[j].end))
{
sum += (S-T[j].end)/2+1 ;
S = T[j].end;
}
else
{
sum += (S-T[j].end+1)/2 ;
S = T[j].end-1;
}
}
}
else
{
if((T[j].star - S)%2==0)
{
sum += (T[j].star - S)/2;
S = T[j].star;
}
else
{
if(T[j].star>T[j+1].star||T[j].star==T[j].end)
{
sum += (T[j].star - S)/2+1 ;
S = T[j].star;
}
else
{
sum += (T[j].star - S + 1)/2 ;
S = T[j].star+1;
}
}
}
}
if(S<T[T.size()-1].star)sum += (T[T.size()-1].star +1-S)/2;
else sum += (S- T[T.size()-1].end +1)/2;
}
cout<<sum<<endl;
}
return 0;
}