piotr_ants蚂蚁相遇问题练习

算法竞赛入门经典的一道题

Sample Input

2
10 1 4
1 R
5 R
3 L
10 R
10 2 3
4 R
5 L
8 R

Sample Output
Case #1:
2 Turning
6 R
2 Turning
Fell off

Case #2:
3 L
6 R
10 R

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

分析:在远处观察蚂蚁运动,由于黑点太小,所以当蚂蚁碰撞掉头时,看上去和两个点“对穿而过”没有任何区别。换句话说,如果把蚂蚁看成没有区别的小点,那么只需独立计算出每只蚂蚁在T时刻的位置即可。比如,3只蚂蚁,蚂蚁1=(3,R),蚂蚁2=(3,L),蚂蚁3=(4,L),则两秒钟之后,3只蚂蚁分别为(5,R),(1,L)和(2,L)。
而且所有蚂蚁的相对顺序保持不变,因此把所有目标位置从小到大排序,则从左到右的每个位置对应于初始状态下从左到右的每只蚂蚁。由于原题中的蚂蚁不一定按照从左到右的顺序输入,还需要预处理计算出输入中的第i只蚂蚁的序号order[i]。


/*
 * =====================================================================================
 *
 *       Filename:  piotr_ants.c
 *
 *    Description:  蚂蚁问题
 *
 *        Version:  1.0
 *        Created:  2014年04月30日 21时46分02秒
 *       Revision:  none
 *       Compiler:  gcc
 * =====================================================================================
 */
#include<stdio.h>
#define MAX 1000
struct ant{
	int id;
	int pos;
	int dir;
}A[MAX],B[MAX];
int cmp(const void *a,const void *b);
int order[MAX];
int main(){
	char dirname[][10]={"L","Turning","R"};
	int m,i;
	scanf("%d",&m);
	for(i=0;i<m;i++){
		int L,T,n;
		int j,tem;
		scanf("%d%d%d",&L,&T,&n);
		for(j=0;j<n;j++){
			char t;
			int p;
			scanf("%d %c",&p,&t);


			A[j].id=j;
			A[j].pos=p;
			A[j].dir=(t=='L'?-1:1);


			B[j].id=0;
			B[j].pos=p+T*(A[j].dir);
			B[j].dir=A[j].dir;
		}
		qsort(A,j,sizeof(A[0]),cmp);
		for(j=0;j<n;j++){
			tem=A[j].id;
			order[tem]=j;
		}
		qsort(B,j,sizeof(A[0]),cmp);
		for(j=0;j<n-1;j++){
			if(B[j].pos==B[j+1].pos)	B[j].dir=B[j+1].dir=0;
		}
		for(j=0;j<n;j++){
			int a=order[j];
			if(B[a].pos<0||B[a].pos>L){
				printf("Fell off\n");
			}else{
				tem=B[a].dir+1;
				printf("%d %s\n",B[a].pos,dirname[tem]);
			}
		}
		printf("\n");
	}
	return 0;
}
int cmp(const void *a,const void *b){
	struct ant *v1=(struct ant *)a;
	struct ant *v2=(struct ant *)b;
	return (v1->pos-v2->pos);
}

看了很久终于弄明白了。主要思想是蚂蚁在相邻两个蚂蚁中间,所以蚂蚁前后都会被挡住,所以蚂蚁的顺序不会变,所以记录其顺序,就能进行处理。原题给的c++的写法。我重新写了一个c的版本,就决问题以后感觉好舒畅!




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值