[USACO2020Dec銅組第三題]奶牛啃草(Stuck in a Rut)
技術標籤:usaco
題目描述
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
解題思路
- 用一個vis陣列存放每頭奶牛最後被攔截時間
- 輸入之後進行迴圈判斷,判斷某頭奶牛是否會被其他奶牛攔截,將情況存放到二維陣列中
- 找到其中不為0的(不為0表示能夠攔截)存放到動態陣列(攔截數量不定,用動態更好)中
- 按被攔截的時間進行排序(時間小的先發生)
- 找到最小時間
#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;
}
時間比較少,程式碼後面就沒進行簡化,很多地方可以進行再簡化