UVA - 10881(思维题)------蚂蚁走竹竿

题意:在这个题中。给了你竹竿的长度L,给了你蚂蚁的个数n,然后下边n行是每一只蚂蚁的初始位置。问你在T秒之后每一只蚂蚁的位置。

这个题给的时间是3000ms,如果一直要写模拟的话,有点烦人。其实,做这道题的时候,我们可以参考挑战书上的一道Ants题。当两只蚂蚁碰撞之后,我们可以将它看为互穿而过,只不过是要改变位置标记。其实,在这道题中,我们可以发现,蚂蚁在同时间是同时进行运动的。那么,它们的相对位置是不会发生改变的。那么,我们就可以对它进行排序。然后记录它的位置。

 

接下来举几个列子 让大家深刻了解一下

10 2 4
1 R
5 R
3 L
10 R

|__*__|__*__|__*__|__|__|__|__*               //将已有位置进行了星号标记
0  1  2  3  4  5  6  7  8  9  10
   ->   <-     ->             ->

我们可以有上图得到 在2秒之后的具体分布情况

|__*__|__*__|__|__|__*__|__|__|    ....第4只蚂蚁掉下              //将到达位置进行了星号标记
0  1  2  3  4  5  6  7  8  9  10
   <-   ->           ->         

我们可以看到,在1 3 走了一秒之后,它们发生了碰撞。使得1和3掉头继续行走。

其实,我们可以换一种思路。当1和3发生碰撞时,我们可以将其视为互穿而过。此时,我们只需交换1和3的位置标记

在上边这个例子中(没有开始走之前),我们按照位置排序之后它的id编号变为  0 2 1 3


那么,我们就可以用一个order数组来记录变换之后的蚂蚁的位置。进而通过变换后的数组来输出每个蚂蚁的位置。		 		  

可能字面意思说的不太清楚。大家可以看下边的代码。进行理解。(主要理解它的相对位置不会发生改变。然后用一个order来记录位置)。

代码:

#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<math.h>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define pi acos(-1)
#define close ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N=1000000+50;
const int INF=0x3f3f3f3f;
const double EPS = 1e-10;
ll mod = 1e9+7;

struct ant{
	int id;
	int pow;
	int dir;
	bool operator < (const ant &a)const{
		return pow<a.pow;
	}
	//结构体内部定义排序 
}before[MAX_N],after[MAX_N];

int order[MAX_N];  //之前的位置记录 
char Rlt[][10] = {"L","Turning","R","Fell off"};
int main(){
	int t;
	scanf("%d",&t);
	int L,T,n,k = 1;
	while(t--){
		printf("Case #%d:\n",k++);
		scanf("%d%d%d",&L,&T,&n);
		int pow;
		char c;
		for(int i = 0; i < n ; i++){
			scanf("%d %c",&pow,&c);
			int dir = (c == 'L'?-1:1);
			before[i] = (ant){i,pow,dir};  
			after[i] = (ant){0,pow + T * dir,dir};
		}
		sort(before,before+n);
		sort(after,after+n);
		
		for(int i = 0; i < n; i++){
			order[before[i].id] = i;
		}
		
		for(int i = 0; i < n - 1; i++){
			if(after[i].pow == after[i+1].pow) after[i].dir = after[i+1].dir = 0;
		}
		
		for(int i = 0; i < n; i++){
			int a = order[i];
			if(after[a].pow < 0 || after[a].pow > L) printf("%s\n",Rlt[3]);
			else printf("%d %s\n",after[a].pow,Rlt[after[a].dir + 1]);
		}
		 printf("\n");
	}

 	return 0;
}

/*
                ********
               ************
               ####....#.
             #..###.....##....
             ###.......######              ###            ###
                ...........               #...#          #...#
               ##*#######                 #.#.#          #.#.#
            ####*******######             #.#.#          #.#.#
           ...#***.****.*###....          #...#          #...#
           ....**********##.....           ###            ###
           ....****    *****....
             ####        ####
           ######        ######
##############################################################
#...#......#.##...#......#.##...#......#.##------------------#
###########################################------------------#
#..#....#....##..#....#....##..#....#....#####################
##########################################    #----------#
#.....#......##.....#......##.....#......#    #----------#
##########################################    #----------#
#.#..#....#..##.#..#....#..##.#..#....#..#    #----------#
##########################################    ############
*/

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃货智

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值