问题描述
长100厘米的细长直杆子上有n只蚂蚁。它们的头有的朝左,有的朝右。
每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。
当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。
这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。
请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。
输入格式
第一行输入一个整数n (1 < n < 50), 表示蚂蚁的总数。
接着的一行是n个用空格分开的整数 Xi (-100 < Xi < 100), Xi的绝对值,表示蚂蚁离开杆子左边端点的距离。正值表示头朝右,负值表示头朝左,数据中不会出现0值,也不会出现两只蚂蚁占用同一位置。其中,第一个数据代表的蚂蚁感冒了。
输出格式
要求输出1个整数,表示最后感冒蚂蚁的数目。
样例输入
3
5 -2 8
样例输出
1
样例输入
5
-10 8 -20 12 25
样例输出
3
思想:首先我们知道,如果一对蚂蚁互相面对着,则这两只蚂蚁的左右两只蚂蚁一定不会和他们面对。
算法1、我们找出所有蚂蚁对(互相面对着)距离最小的(可能有多对)为minn,
2、所有蚂蚁移动minn/2个距离
3、并且把距离最小的蚂蚁对,方向置反,更新感染状态,
4、还有面对着的蚂蚁,或剩余蚂蚁数不为0,继续执行1,否则结束
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct ant{ //蚂蚁结构体
double loc;
int dir;
int inf;
ant(double ll,int dd,int ii){
loc = ll;
dir = dd;
inf = ii;
}
};
bool cmp(const ant&a,const ant&b){
return a.loc < b.loc;
}
vector<ant>vc; //记录所有蚂蚁
int main(){
int n;
cin>>n;
for(int i = 0;i < n;i++){ //更新vc
int t;
cin>>t;
if(t < 0){
if(i == 0){
vc.push_back(ant(abs(t),-1,1));
}else{
vc.push_back(ant(abs(t),-1,0));
}
}else{
if(i == 0){
vc.push_back(ant(abs(t),1,1));
}else{
vc.push_back(ant(abs(t),1,0));
}
}
}
sort(vc.begin(),vc.end(),cmp); //按蚂蚁位置从小到大排序
int l = 0;//指向最左边的蚂蚁
int r = vc.size() - 1;//指向最右边的蚂蚁
while(l < r){ //蚂蚁数不为0时
vector<int>tvc; //记录距离最小的蚂蚁对,可能有多个
double minn = 666;
for(int i = l;i < r;i++){
if(vc[i].dir == 1 && vc[i+1].dir == -1 ){ //互相面对的蚂蚁对
if(minn > vc[i + 1].loc - vc[i].loc){
while(tvc.size() != 0){ //当找到一个距离更小的,就把之前最小的记录全部删除
tvc.pop_back();
}
tvc.push_back(i);
minn = vc[i + 1].loc - vc[i].loc;
}else{
if(minn == vc[i + 1].loc - vc[i].loc){ //找到不只一个最小的,也记录到tvc中(只记录左端点)
tvc.push_back(i);
}
}
}
}
if(tvc.size() == 0){ //没有找到蚂蚁对
break;
}
int ll = l;
int rr = r;
for(int i = ll;i <= rr;i++){ //移动左右蚂蚁minn/2个距离
if(vc[i].dir == 1){
vc[i].loc += minn / 2;
}else{
vc[i].loc -= minn/2;
}
if(vc[i].loc >= 100){ //最右边蚂蚁越界
r--;
}else{
if(vc[i].loc <= 0){ //最左边蚂蚁越界
l++;
}
}
}
int ts = tvc.size();
for(int i = ts - 1;i >= 0;i--){ //更新要面对的蚂蚁对的状态(方向和感染状态)
if(vc[tvc[i]].inf || vc[tvc[i] + 1].inf){ //有一个感染,就全部感染
vc[tvc[i]].inf = 1;
vc[tvc[i] + 1].inf = 1;
}
vc[tvc[i]].dir *= -1; //方向置反
vc[tvc[i] + 1].dir *= -1; //f方向置反
tvc.pop_back(); //删除记录(必须有,为了置空数组,为下次使用)
}
}
int sum = 0;
for(int i = 0;i < n;i++){ //统计感染数
if(vc[i].inf){
sum++;
}
}
cout<<sum;
return 0;
}