学习C++从娃娃抓起!记录下USACO(美国信息学奥赛)备考青铜组别比赛学习过程中的题目,记录每一个瞬间。
附上汇总贴:USACO历年青铜组真题解析 | 汇总-CSDN博客
【题目描述】
为了准备即将到来的蹄球锦标赛,Farmer John正在训练他的N头奶牛(方便起见,编号为1…N,其中1≤N≤100)进行传球。这些奶牛在牛棚一侧沿直线排列,第i号奶牛位于距离牛棚xi的地方(1≤xi≤1000)。每头奶牛都在不同的位置上。
在训练开始的时候,Farmer John会将若干个球传给不同的奶牛。当第i号奶牛接到球时,无论是从Farmer John或是从另一头奶牛传来的,她会将球传给最近的奶牛(如果有多头奶牛与她距离相同,她会传给其中距左边最远的那头奶牛)。为了使所有奶牛都有机会练习到传球,Farmer John想要确保每头奶牛都持球至少一次。帮助他求出为了达到这一目的他开始时至少要传出的球的数量。假设他在开始的时候能将球传给最适当的一组奶牛。
【输入】
输入的第一行包含N。第二行包含N个用空格分隔的整数,其中第i个整数为xi。
【输出】
输出Farmer John开始的时候最少需要传出的球的数量,使得所有奶牛至少持球一次。
【输入样例】
5
7 1 3 11 4
【输出样例】
2
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, a[105], cnt[105], nxt[105], ans=0;
ifstream filein("hoofball.in");
ofstream fileout("hoofball.out");
int main()
{
filein >> n; // 输入n
for (int i=1; i<=n; i++) { // 依次输入n个数
filein >> a[i];
}
sort(a+1, a+n+1); // 对数进行排序
nxt[1] = 2; // 默认左端点放一个球
cnt[2] = 1; // 指向右边一个端点
nxt[n] = n-1; // 默认右端点放一个球
cnt[n-1] = 1; // 指向左边一个端点
for (int i=2; i<n; i++) { // 从第2个球开始遍历
if (a[i]-a[i-1] > a[i+1]-a[i]) { // 比较向左的距离和向右的距离,如果向右距离更短
nxt[i] = i+1; // 则向右移动
cnt[i+1]++; // 右边那个球的计数器自增1
} else { // 如果向左距离更短
nxt[i] = i-1; // 则向左移动
cnt[i-1]++; // 左边那个球的计数器自增1
}
}
for (int i=1; i<=n; i++) { // 先遍历一遍n个奶牛
if (cnt[i]==0) ans++; // 哪些计数为0的奶牛就是把球放这个位置后不再回头的位置(即可以放球的位置)
}
for (int i=1; i<n; i++) { // 再遍历一遍n-1个奶牛(因为要判断i+1,所以i不能等于n)
if (cnt[i]==1 && cnt[i+1]==1 && nxt[i]==i+1 && nxt[i+1]==i) ans++; // 对于两个奶牛的nxt互相指向对方的,且cnt均为1(表示一上来就互相指向对方,而不是经历多轮遍历后才互相指向对方的),这样的一对奶牛需要单独再放一个球
}
fileout << ans << endl; // 打印结果
return 0;
}
【运行结果】
5
7 1 3 11 4
2