【蓝桥杯】蚂蚁感冒(C++)

问题描述
  长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;
} 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值