UVA - 10881 - Piotr's Ants

本文介绍了一种模拟多个蚂蚁在单杠上爬行并处理碰撞转向的算法。通过记录蚂蚁初始位置和方向,模拟指定时间后的状态,实现了碰撞处理并正确输出每个蚂蚁的位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门:

    http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=25979

题意:

    蚂蚁在单杠上爬,互相碰撞就转向。输入杠长,持续时间,还有蚂蚁数量。最后得出所有蚂蚁的位置。

    ① 蚂蚁因碰撞而掉头时,看上去就是两个点“对穿而过”。

    ② 如,蚂蚁点A(1,R),在碰撞的两秒后,存在点A'(3,R),只是(3,R)是另外一只蚂蚁。A与A'方向一样。

    ③ 其实无论怎么碰撞,原本在杠上的顺序abcdefg,碰撞后还是abcdefg的顺序,而且原本的顺序。

    ④ 只需要按照原来的顺序和方向,计算出N秒后各个点的位置(计算时,方向保持不变),再套用原来的顺序abcdefg,从左到右套用在N秒后的顺序上即可。

    ⑤ 根据输入的顺序,对应输出结果。不是简单的从左到右。所以要保存好原来的输入顺序,用数组做好映射(Mapping)。

注意:

    ① 要根据输入的顺序,输出对应蚂蚁的位置结果。

思路:

    ① 保存原有状态(位置和方向)

    ② 根据位置,从左到右排序出结果;并使用数组实现从“原输入顺序的id”到“排序后的id”的映射。

    ③ 模拟N秒后的状态,并进行位置的排序。

    ④ 根据原有从左到右的id,分配到N秒后的顺序上。结合“映射”按顺序输出结果。

总结:

    ① 智商低,就是更要多看看别人代码,学学思想;静下心来思考。

    ② 定义类或结构体的时候,用其来声明数组时,有时会出错;因为没有定义一个默认构造函数(无参数)。

    ③ 适当把输出文本放在数组里,根据结果对应输出数组内容,快速、而且方便管理。

    ④ 在进行“==”操作对比时,居然用数字比'R',或者字母比'1';不要以为‘==’两边顺其自然就是同类型数据,要理解各位置各变量的内容!低级错误不能有。



STL版本<使用list和stack>:Memery 0 KB/Time 129 ms

#include <iostream>
#include <algorithm>
#include <stdio.h>

using namespace std;

// Local Test
// #define LOCAL_TEST


// used to define Array
const int MAX_SIZE = 10000 + 2;


// define class CAnt
// "before" array store original "InputOrder" and position/direction
struct CAnt
{
	// InputOrder number
	int id;
	// Position on pole
	int pos;
	// Direction, "-1" means "left", "0" means "turning", "1" means "right"
	int dir;
	// constructed function
	CAnt(int a, int b, int c):id(a), pos(b), dir(c){}
	// If define array, class needs a constructed function
	// for setting default value
	CAnt(){id=0; pos=0; dir=0;}
	// operator for "sort" function
	bool operator < (const CAnt &b){return pos<b.pos;}
} before[MAX_SIZE], after[MAX_SIZE];

// A Mapping for turning "InputOrder number" to the sorted array's index
int mpInOrderToSorted[MAX_SIZE];
// faster Mapping from "index" to "direction string"
char outStr[][10] = {"L", "Turning", "R"};


int main()
{
#ifdef LOCAL_TEST
	freopen("..\\in.txt", "r", stdin);
	freopen("..\\out.txt", "w+", stdout);
#endif
	// ------- Solution by using Sync(false)
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);

	// Store the number of Cases
	int nCase;
	cin >>nCase;
	// Every case processing
	for ( int index=0; index<nCase; index++ )
	{
		// Get "maxLen", the length of pole
		// Get "timePass", the time passed
		// Get "nAnts", the number of Ants
		int maxLen, timePass, nAnts;
		cin >>maxLen >>timePass >>nAnts;
		// Get input data
		for ( int i=0; i<nAnts; i++ )
		{
			// the current "i" means the inputOrder
			int id = i;
			// Get position(integer) and direction(char)
			int pos;
			char c;
			cin >>pos >>c;
			// char to integer.
			// Take care of 'R' (letter with single quotes mark)
			int dir = (c=='R'?1:-1);
			// store data to "before" array
			before[i] = CAnt(id, pos, dir);
			// use easy formula "pos+dir*timepass"
			// to calculate the positions after the time
			// By the way, directions remain unchanged
			after[i] = CAnt(0, pos+dir*timePass, dir);
		} // end for

		// 'Cause "inputOrder" is out of order From left to right on the pole
		// We need to sort the array data.
		// From the sorted array, we can get a order sequence while it means
		// the current order and the future order(they're the same)
		sort(before, before+nAnts);
		// After sorted, we miss the inputOrder,
		// use another array to store a Mapping
		// From "InputOrder"[0~n] to "poleOrder"(current or future)
		for ( int i=0; i<nAnts; i++ )
			mpInOrderToSorted[before[i].id] = i;

		// sort the array after moving
		// Get the final Ants' position
		sort(after, after+nAnts);
		// while neighbour Ants together means "Turning" direction
		// Set to "0"
		for ( int i=0; i<nAnts-1; i++ )
			if ( after[i].pos == after[i+1].pos )
				after[i].dir = after[i+1].dir = 0;

		cout <<"Case #" <<index+1 <<":" <<endl;
		for ( int i=0; i<nAnts; i++ )
		{
			int a = mpInOrderToSorted[i];
			if ( after[a].pos<0	|| after[a].pos>maxLen )
				cout <<"Fell off" <<endl;
			else
				cout <<after[a].pos <<" " <<outStr[after[a].dir+1] <<endl;
		} // end for
		cout <<endl;
	} // end for

	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值