例题1.5 蚂蚁 UVA - 10881 等效变换+排序

传送门


题目大意:一根长度为L的杆上有N只蚂蚁,每只蚂蚁要么往左爬,要么往右爬,速度为1.两只蚂蚁相撞,同时掉头。杆子最左端为0,问T间时各蚂蚁的位置和方向。


解题思路:两只蚂蚁相撞与穿过效果一样。因此我们直接计算蚂蚁相遇直接穿过的结果即可。但是我们需要记录每只蚂蚁的方向,其实我们按照穿过计算时,朝左的个数和朝右的个数以及顺序不会变,但是蚂蚁的位置变了,但是真正蚂蚁的相对位置没有变,即最左边的还在最左边,左边第二个还在左边第二个。因此我们只需给蚂蚁加一个编号,按照编号给蚂蚁在更新一下状态即可。比如:有一个蚂蚁在排第三,但是它朝左走了之后变成了第一个,那么原来第一个蚂蚁的状态就是现在这个蚂蚁的状态。我们只需将现在的顺序更新到之前的蚂蚁身上即可。


AC代码:

#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>

using namespace std;

struct Ants
{
	int x;
	int id;
	int z;	
	bool operator< (Ants a)const
	{
		return this->x < a.x;
	}
	
}A[10005];

map<int, int> mp;


int main()
{
	int T;
	cin >> T;
	for(int Case = 1; Case <= T; Case++)
	{
		mp.clear();
		int l, t, n;
		scanf("%d%d%d", &l, &t, &n);
		char s[10];
		int x;
		for(int i=0; i<n; i++)
		{
			scanf("%d%s", &x, s);
			A[i].id = i;
			if(s[0] == 'R') A[i].z = 1;  //朝右走 
			else A[i].z = -1; //朝左走 
			A[i].x = x;
		}
		sort(A, A+n);//让蚂蚁从左到右站好 
		for(int i=0; i<n; i++)
		{
			mp[ A[i].id ] = i; //记录原来蚂蚁的顺序 
			A[i].x += A[i].z * t;//更新位置 
		}
		sort(A, A+n);//更新顺序 
		printf("Case #%d:\n", Case);
		for(int i=0; i<n; i++)
		{
			int cur = mp[i];
			if(A[cur].x < 0 || A[cur].x > l) printf("Fell off\n");  //从杆子上掉下来了 
			else if(cur +1 < n && A[cur].x == A[cur+1].x)    //判断是否右跟这个蚂蚁在同一个位置的 
			{
				if(A[cur].z + A[cur+1].z == 0) printf("%d Turning\n", A[cur].x); //位置相同,方向相反,正在相撞 
				else if(A[cur].z == -1) printf("%d L\n", A[cur].x);
				else printf("%d R\n", A[cur].x);
			}
			else if(cur -1 < n && A[cur].x == A[cur-1].x)       //判断是否右跟这个蚂蚁在同一个位置的
			{
				if(A[cur].z + A[cur-1].z == 0) printf("%d Turning\n", A[cur].x);  //正在相撞 
				else if(A[cur].z == -1) printf("%d L\n", A[cur].x);
				else printf("%d R\n", A[cur].x);
			}
			else 
			{
				if(A[cur].z == -1) printf("%d L\n", A[cur].x);
				else printf("%d R\n", A[cur].x);
			}
		}
		printf("\n");
	}
	return 0;
} 

蓝书代码:

// UVa10881 Piotr's Ants
// Rujia Liu
#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn = 10000 + 5;

struct Ant {
  int id; // 输入顺序
  int p;  // 位置
  int d;  // 朝向。 -1: 左; 0:转身中; 1:右
  bool operator < (const Ant& a) const {
    return p < a.p;
  }
} before[maxn], after[maxn];

const char dirName[][10] = {"L", "Turning", "R"};

int order[maxn]; // 输入的第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] = (Ant){i, p, d};
      after[i] = (Ant){0, p+T*d, d}; // 这里的id是未知的
    }

    // 计算order数组
    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;

    // 输出结果
    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]);
    }
    printf("\n");
  }
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值