题目:The Last Ant
长度为L的管道里N只蚂蚁,管道一节窄一节宽,所有蚂蚁的速度都相同,一开始蚂蚁都在窄的地方。如果两只蚂蚁在宽的地方碰头,则擦肩而过,否则各自掉转方向。求最后一只蚂蚁离开的时间以及离开的编号,如果有同时离开(一左一右),则输出左边的编号。
背景还是经典的蚂蚁问题(《训练指南》里有提到),先不考虑蚂蚁的编号,只把蚂蚁当作黑点,擦肩而过跟掉转方向其实都可以看作前者,所以可以直接计算出每个黑点离开的时间,最晚的肯定就是最后离开的时间。
而题目中管道长度不超过100,蚂蚁速度为1,那么时间上来说就顶多就100,而蚂蚁最多20只,所以可以直接按照时间进行模拟,处理好碰头的事就OK了。
我处理的方式是先把管道放大为原先的两倍,那么原先的0.5s就变成1s,这样模拟起来比较容易。
然后就用used[]数组来判断某个位置是否有蚂蚁,如果一只蚂蚁走进一个位置并且该位置为窄(时间上来说就是偶数时间,起始时刻为0),那么两只蚂蚁掉头。
#include<cstdio>
#include<cstring>
char s[10];
int d[30], p[30];
bool flag[30];
int used[210];
int main(){
int n, L;
while(~scanf("%d %d", &n, &L) && (n||L)){
int m = 0;
int t = 0;
L*=2;
for(int i=0; i<n; i++){
flag[i] = 0;//flag表示蚂蚁是否离开
scanf("%s %d", s, p+i);
p[i]*=2;
if(s[0]=='L'){
t = p[i];
d[i] = 0;
}
else{
t = L-p[i];
d[i] = 1;
}
if(t>m) m=t;
}
int id, cur=-1;
for(int i=1; i<=m; i++){
memset(used, -1, sizeof(used));
for(int j=0; j<n; j++){
if(flag[j]) continue;
if(d[j]==0){
p[j]--;
if(p[j]==0){
flag[j] = 1;
if(i>=cur){
cur = i;
id = j;
}
}
else if(used[p[j]]==-1){
used[p[j]] = j;
}
else if(i%2==0){
d[j]^=1;
d[used[p[j]]]^=1;
}
}
else{
p[j]++;
if(p[j]==L){
flag[j] = 1;
if(i>cur){
cur = i;
id = j;
}
}
else if(used[p[j]]==-1){
used[p[j]]=j;
}
else if(i%2==0){
d[j]^=1;
d[used[p[j]]]^=1;
}
}
}
/*
printf("time: %d\n", i);
for(int j=0; j<n; j++){
printf("%d %d\n", d[j], p[j]);
}
*/
}
printf("%d %d\n", m/2, id+1);
}
return 0;
}