蚂蚁(对穿而过 思维题)

本文介绍了两道与蚂蚁行为相关的编程题。第一题涉及蚂蚁在木棍上爬行并碰撞转向的问题,第二题是关于感冒在蚂蚁间传播的模拟。解题关键在于理解蚂蚁碰撞时的状态变化,并通过排序和遍历确定最终位置。AC代码给出了详细的解决方案。
摘要由CSDN通过智能技术生成

题目:

一根长L厘米的木棍上有n只蚂蚁,每只蚂蚁要么朝左爬,要么朝右爬,速度为1cm/s。当两只蚂蚁相撞时,二者同时掉头。给出每只蚂蚁的初始位置和朝向,计算T秒之后每只蚂蚁的位置。

对于每组数据,按输入顺序输出每只蚂蚁的位置和朝向,Turning表示正在碰撞。在第T秒之前已经掉下木棍的蚂蚁(正好爬到木棍边缘的不算)输出Fell off。

样例输入

2

10 1 4

1 R

5 R

3 L

10 R

10 2 3

4 R

5 L

8 R

样例输出:

Case #1:

2 Turning

6 R

2 Turning

Fell off

Case #2:

3 L

6 R

10 R

思路:

当蚂蚁因碰撞而掉头时,看上去像两个点”对穿而过“ ,那么如果把蚂蚁看成小点,就只需要独立计算出每只蚂蚁T秒之后的位置即可。

但是,整体看来是”对穿而过“,对于每一只蚂蚁可不是这样。蚂蚁1的初始状态为(1,R),因此一定有一只蚂蚁在2s之后处于(3,R)的状态,但是这只蚂蚁不一定是蚂蚁1。因此我们需要搞清楚目标状态中”谁是谁“。

因此,所有蚂蚁的相对顺序是不变的。

将所有蚂蚁目标位置从小到大排序,则从左到右的每个位置对应于初始状态下从左到右的每只蚂蚁。因为题目中不一定按蚂蚁从左到右的顺序输入,因此需要预处理出输入中的第i只蚂蚁的序号order[i].

步骤:

先保存两个结构体数组:一个是初始位置的before数组,另一个是T秒之后的目标位置的after数组。

先对before数组按位置从左到右排序,处理出输入中的第i只蚂蚁的序号order[i].

再对after数组按位置从左到右排序,之后从头开始遍历,每次和下一个比较,如果位置相同表明正在Turning。

因为要按输入顺序输出每只蚂蚁的位置和朝向,所以每次取序号a=order[i],先判断这只蚂蚁是否已经掉下去,如果没有,再输出它的位置after[a].p和状态dirName[after[a].d+1]。

AC代码:


#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
struct node{
	int id;//输入顺序 
	int p;//位置 
	int d;//朝向 -1:左 0:turning 1:右 
	//按位置从左到右排序 
	bool operator<(const node& a)const{
	     return p<a.p;}
}before[N],after[N];
//储存状态名称 
char dirName[][15]={"L","Turning","R"};
int order[N];//输入的第i只蚂蚁是终态中的左数第order[i]只蚂蚁 

int main(){
	int k;
	scanf("%d",&k);
	for(int kase=1;kase<=k;kase++){
		int L,T,n;
		printf("Case #%d:\n",kase);
		scanf("%d%d%d",&L,&T,&n);
		for(int i=0;i<n;i++){
			int p,d;
			char c;
			scanf("%d %c",&p,&c);
			d=(c=='L'?-1:1);
			//初始数组 
			before[i]=(node){i,p,d};
			//目标数组 
			after[i]=(node){0,p+T*d,d};//这里的id是未知的 
		}
		sort(before,before+n);//这个拿来确定顺序 
		for(int i=0;i<n;i++){
			order[before[i].id]=i;
		}
		sort(after,after+n);//计算终态 
		//修改状态 
		for(int i=0;i<n-1;i++){
			if(after[i].p==after[i+1].p){//相碰 
				after[i].d=after[i+1].d=0;//修改为Turning状态 
			}
		}
		for(int i=0;i<n;i++){
			int a=order[i];//按输入顺序来
			//如果已经掉下 
			if(after[a].p<0||after[a].p>L) printf("Fell off\n");
			else printf("%d %s\n",after[a].p,dirName[after[a].d+1]);
		}
		puts("");
	}
	return 0;
}

类似穿墙而过的思路的还有2014年蓝桥杯的这道题:

第七题:蚂蚁感冒


题目描述


长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

分析:
对对碰==穿过对方。
如果最初感冒的蚂蚁向右,那么它右边的所有反向的蚂蚁都将被感染。
如果右边存在和它碰头的蚂蚁,它就会反向,那么此时它后面的
原来和它同向的蚂蚁都将被感染。

向左思路类似。

AC代码:

#include <bits/stdc++.h>
using namespace  std;
const int N = 1e6+10;
int a[N],n;
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	int x=a[0];
	if(x>0){//如果感冒的蚂蚁向右
	    int ans=1;//最初感冒的蚂蚁只有1只 
		for(int i=0;i<n;i++){
			if(a[i]<0&&-a[i]>x){//找反向的在它前面的蚂蚁 
				ans++;
			}
		}
		if(ans!=1){//如果对碰了,会反向 
			for(int i=0;i<n;i++){
				if(a[i]>0&&a[i]<x){//找同向的在它后面的蚂蚁 
					ans++;
				}
			}
		}
		printf("%d",ans);
	}
	else if(x<0){//如果感冒的蚂蚁向左 
	    int ans=1;//最初感冒的蚂蚁只有1只 
		for(int i=0;i<n;i++){
			if(a[i]>0&&a[i]<-x){//找在它后面的反向的蚂蚁 
				ans++;
			}
		}
		if(ans!=1){//如果对碰了 
			for(int i=0;i<n;i++){
				if(a[i]<0&&-a[i]>-x){//找在它前面的同向的蚂蚁 
					ans++;
				}
			}
		}
		printf("%d",ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值