题解:B4160 [BCSP-X 2024 12 月小学高年级组] 排座位
wangxiaochai · · 题解
读完题很容易想到这是一道贪心题。问题在于怎么个贪法。
91 分做法:
要贪心就要先把小朋友们的座位区间进行排序。排序规则是先按右边界从小到大排序,如果相同就把左边界从大到小排序。这样我们每次都会优先处理座位区间最短的小朋友,使我们可选的座位最大。
根据上面这个思路,很容易就写出了如下代码:
for (int i=1; i<=n; i++)
{
memset(seat,0,sizeof(seat));
int cnt = 0;
for (int j=1; j<=m; j++)
{
for (int k=a[j].l; k<=min(a[j].r,i); k++)
{
if (!seat[k])
{
seat[k] = 1;
cnt++;
break;
}
}
}
cout << cnt << '\n';
}
因为题目让我们分别求座位数
100 分做法:
既然贪心思路没问题,接下来考虑怎么优化算法。
对于查找可以坐的座位时,原算法是枚举
初始时,每个座位的父节点指向自己。根据前文提到
核心代码:
// 初始化并查集
for (int i = 0; i <= n + 1; i++)
parent[i] = i;
// 处理每个区间
for (int i = 0; i < m; i++)
{
int l_val = a[i].l;
int r_val = a[i].r;
int s = find(l_val); // 找到当前可用的最大座位
if (s >= l_val && s <= r_val)
{ // 确保座位在有效范围内
cnt[s]++; // 占用该座位
parent[s] = find(s + 1); // 更新并查集,指向下一个可用座位
}
}
在输出的时候,通过前缀和数组记录每个
// 计算前缀和
int current = 0;
for (int k = 1; k <= n; k++)
{
current += cnt[k];
ans[k] = current;
}
// 输出结果
for (int k = 1; k <= n; k++)
cout << ans[k] << "\n";
排序算法是
这样这道题就完美解决了!