[USACO2020Dec铜组第三题]奶牛啃草(Stuck in a Rut)

题目描述
Farmer John 最近扩大了他的农场,从奶牛们的角度看来这个农场相当于是无限大了!奶牛们将农场上放牧的区域想作是一个由正方形方格组成的无限大二维方阵,每个方格中均有美味的草(将每个方格看作是棋盘上的一个方格)。Farmer John 的 N 头奶牛(1≤N≤50)初始时位于不同的方格中,一部分朝向北面,一部分朝向东面。

每一小时,每头奶牛会执行以下二者之一:
如果她当前所在的方格里的草已经被其他奶牛吃掉了,则她会停下。
吃完她当前所在的方格中的所有草,并向她朝向的方向移动一个方格。

经过一段时间,每头奶牛的身后会留下一条被啃秃了的轨迹。

如果两头奶牛在一次移动中移动到了同一个有草的方格,她们会分享这个方格中的草,并在下一个小时继续沿她们朝向的方向移动。

请求出每头奶牛吃到的草的数量。有些奶牛永远不会停下,从而吃到无限多的草。

输入
输入的第一行包含 N。以下 N 行,每行描述一头奶牛的起始位置,包含一个字符 N(表示朝向北面) 或 E(表示朝向东面),以及两个非负整数 x 和 y(0≤x≤109,0≤y≤109)表示方格的坐标。所有 x 坐标各不相同,所有 y 坐标各不相同。
为了使方向和坐标尽可能明确,如果一头奶牛位于方格 (x,y) 并向北移动,她会到达方格 (x,y+1)。如果她向东移动,她会到达方格 (x+1,y)。
输出
输出 N 行。输出的第 i 行包含输入中的第 i 头奶牛吃到草的方格的数量。如果一头奶牛可以吃到无限多的草,为这头奶牛输出 “Infinity”。

样例输入
6
E 3 5
N 5 3
E 4 6
E 10 4
N 11 2
N 8 1
样例输出
5
3
Infinity
Infinity
2
5

解题思路

  1. 用一个vis数组存放每头奶牛最后被拦截时间
  2. 输入之后进行循环判断,判断某头奶牛是否会被其他奶牛拦截,将情况存放到二维数组中
  3. 找到其中不为0的(不为0表示能够拦截)存放到动态数组(拦截数量不定,用动态更好)中
  4. 按被拦截的时间进行排序(时间小的先发生)
  5. 找到最小时间
#include <bits/stdc++.h>
using namespace std;
struct Cow {
	char f;//方向
	int x;
	int y;
	int t;//被拦截时间
} cow[60];
vector<Cow>que;
int n,cc[60][60];//cc[i][j]:第i头牛被第j头牛在第cc[i][j]时刻拦住
int vis[60];
const int INF=INT_MAX;
bool cmp(Cow x,Cow y) {//按被拦截时间进行排序
	return x.t<y.t;
}
int main() {
	cin>>n;
	fill(vis+1,vis+n+1,INF);//初始化被拦截时间
	for(int i=1; i<=n; i++) {
		cin>>cow[i].f>>cow[i].x>>cow[i].y;
	}
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
			if(i==j||cow[i].f==cow[j].f) continue;
			if(cow[i].f=='E'&&cow[j].f=='N') {//第i头牛向东移,第j头牛向北移
				if(cow[i].y>=cow[j].y&&cow[j].x>=cow[i].x)//初始位置判断
					if(cow[i].y-cow[j].y<cow[j].x-cow[i].x)//第j头牛要先到达拦截点:j北移距离>i东移距离
						cc[i][j]=cow[j].x-cow[i].x;
			} else {//理由跟上类似
				if(cow[j].y>=cow[i].y&&cow[i].x>=cow[j].x)
					if(cow[j].y-cow[i].y>cow[i].x-cow[j].x)
						cc[i][j]=cow[j].y-cow[i].y;
			}
		}
	}
	for(int i=1; i<=n; i++) {//找到能够拦截的存放到一维数组中
		for(int j=1; j<=n; j++) {
			if(cc[i][j]==0) continue;
			Cow zz;
			zz.x=i,zz.y=j,zz.t=cc[i][j],zz.f=cow[i].f;
			que.push_back(zz);
		}
	}
	sort(que.begin(),que.end(),cmp);//被拦截时间排序
	for(int i=0; i<que.size(); i++) {
		if(que[i].t<=vis[que[i].y]) {//i的被拦截时间 < 拦截i的牛的被拦截时间时,直接更新
			vis[que[i].x]=min(vis[que[i].x],que[i].t);
		} else {//被拦截时间大于等于时,也有可能被拦截,需判断初始位置
			if(que[i].f=='E') {
				if(cow[que[i].y].y+vis[que[i].y]<cow[que[i].x].y||cow[que[i].y].y>cow[que[i].x].y){
					continue;
				}
			}
			else{
				if(cow[que[i].y].x+vis[que[i].y]<cow[que[i].x].x||cow[que[i].y].x>cow[que[i].x].x){
					continue;
				}
			}
			vis[que[i].x]=min(vis[que[i].x],que[i].t);
		}
	}
	for(int i=1; i<=n; i++) {//如果vis没改变,说明可以一直走下去
		if(vis[i]==INF) cout<<"Infinity"<<endl;
		else cout<<vis[i]<<endl;
	}
	return 0;
}

我懒,代码后面就没进行简化,很多地方可以进行再简化

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值