坠落的蚂蚁
题目描述:
一根长度为1米的木棒上有若干只蚂蚁在爬动。它们的速度为每秒一厘米或静止不动,方向只有两种,向左或者向右。如果两只蚂蚁碰头,则它们立即交换速度并继续爬动。三只蚂蚁碰头,则两边的蚂蚁交换速度,中间的蚂蚁仍然静止。如果它们爬到了木棒的边缘(0或100厘米处)则会从木棒上坠落下去。在某一时刻蚂蚁的位置各不相同且均在整数厘米处(即1,2,3,…99厘米),有且只有一只蚂蚁A速度为0,其他蚂蚁均在向左或向右爬动。给出该时刻木棒上的所有蚂蚁位置和初始速度,找出蚂蚁A从此时刻到坠落所需要的时间。
输入描述:
第一行包含一个整数表示蚂蚁的个数N(2<=N<=99),之后共有N行,每一行描述一只蚂蚁的初始状态。每个初始状态由两个整数组成,中间用空格隔开,第一个数字表示初始位置厘米数P(1<=P<=99),第二个数字表示初始方向,-1表示向左,1表示向右,0表示静止。
输出描述:
蚂蚁A从开始到坠落的时间。若不会坠落,输出“Cannot fall!”
输入:
4
10 1
90 0
95 -1
98 -1
输出:
98
题解:本题最终要的是要理解,一个蚂蚁只会在他左右两边的蚂蚁所圈定的范围内活动,也就是说不论怎么运动,这几个蚂蚁在木棒上的相对顺序是不变的。
首先交换速度的含义不仅仅是交换速度的大小,同时也交换了方向。也就是说蚂蚁碰头后并不会越过对方,而是向反方向继续前进。可以理解为:没有谁能越过对方,所有蚂蚁只能在由左右两只蚂蚁组成的“囚笼”内移动。
找到速度为0的蚂蚁
它左边有left个蚂蚁
右边有right个蚂蚁
如果判断蚂蚁最后向左掉下,那么它必定是第left+1个掉下去的
如果向右掉下,那么必定是第right+1个掉下去的
怎么判断从哪边掉下去呢?
设向左走的蚂蚁有 toleft个
向右走的蚂蚁右 toright个
首先要明白 最后的最后 一定会有toleft个蚂蚁从左边落下,toright个蚂蚁从右边落下。
如果所有向左走的蚂蚁的数量toleft大于left那么静止蚂蚁左边的left个都掉下去了,此时还有蚂蚁要从左边掉下去,那么就轮到了静止的蚂蚁了
如果所有向右走的蚂蚁的数量toright大于right那么静止蚂蚁右边的right个都掉下去了,此时还有蚂蚁要从右边掉下去,那么就轮到了静止的蚂蚁了。
如果向左走的蚂蚁toleft等于left那么就轮不到静止的蚂蚁跳下去
如果向右走的蚂蚁toright等于right那么就轮不到静止的蚂蚁跳下去
现在清楚了如果判断从哪边跳下去,那么时间如何计算呢
如果从左边跳下去,那么可以认为是向左走的蚂蚁中,下标为left的蚂蚁从开始位置走到最左边的时间
如果从右边跳下去,那么可以认为是向右走的蚂蚁中,(right=n-1-left)下标为n-left-1的蚂蚁从开始位置走到最右边的时间。
以下为参考代码:
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
struct Ant
{
int position;
int direct; //方向
};
bool cmp(Ant a,Ant b)
{
return a.position<b.position;
}
int main()
{
int n;
while(scanf("%d",&n) != EOF)
{
vector<Ant> ant(n);
for(int i = 0; i<n; i++)
scanf("%d %d",&ant[i].position,&ant[i].direct);
sort(ant.begin(),ant.end(),cmp);
//接下来要做的就是找到静止的那只的位置,为此我们要先排序
//这样找到的静止的蚂蚁左边有几只就出来了
int target,toLeft = 0; //这里选用向左走的为基准来做
for(int i = 0; i<n; i++) //遍历所有蚂蚁
{
if(ant[i].direct == 0)
target = i;
if(ant[i].direct == -1)
toLeft++;
}//现在的target就是静止的蚂蚁左边的数量了,也就是静止蚂蚁的下标
bool flag = false;
int ans;
if(toLeft == target)
flag = true;
else if (toLeft > target)//这样的话我们要找的就是所有向左走的蚂蚁中,下表为target的蚂蚁
{
int cnt = 0;//计数器
for(int i = 0; i<n; i++)
{
if(ant[i].direct == -1 && cnt == target)
{
ans = ant[i].position;//这只蚂蚁的位置,即为它坠落所需的时间,也就是蚂蚁A坠落的时间
break;
}
else if(ant[i].direct == -1)
cnt++;
}
}
else //向左走的蚂蚁少,那么目标蚂蚁会向右落下
{
int cnt = 0;
for(int i = n - 1; i>=0; i--)
{
if(ant[i].direct == 1 && cnt == n - target - 1)//相应的变化,cnt要变成静止蚂蚁右边的蚂蚁数量
{
ans = 100 - ant[i].position; //由于是向右,就用100减一下
break;
}
else if(ant[i].direct == 1)
cnt++;
}
}
if(flag)
printf("Cannot fall!\n");
else
printf("%d\n",ans);
}//while
return 0;
}
废了不少时间才想明白,趁着还没忘,赶紧记下来。