题解:洛谷 P3029 [USACO11NOV] Cow Lineup S

【题目来源】

洛谷:[P3029 USACO11NOV] Cow Lineup S - 洛谷

【题目描述】

农民约翰雇一个专业摄影师给他的部分牛拍照。由于约翰的牛有好多品种,他喜欢他的照片包含每个品种的至少一头牛。

约翰的牛都站在一条沿线的不同地方, 每一头牛由一个整数位置 \(X_i\) 以及整数品种编号 \(ID_i\) 表示。

约翰想拍一张照片,这照片由沿线的奶牛的连续范围组成。照片的成本与规模相当,这就意味着,在一系列照片中的最大和最小 \(X\) 坐标的差距决定了照片的成本。

请帮助约翰计算最小的照片成本,这些照片中有每个不同的品种的至少一头牛,没有两头牛愿意站在同一个地点的。

【输入】

\(1\) 行:牛的数量 \(N\)

\(2..1+N\) 行:每行包含 2 个以空格分隔的正整数 \(X_i\)\(ID_i\);意义如题目描述;

【输出】

输出共一行,包含每个不同品种 \(ID\) 的照片的最低成本。

【输入样例】

6 
25 7 
26 1 
15 1 
22 3 
20 1 
30 1 

【输出样例】

4

【解题思路】

image

【算法标签】

《洛谷 P3029 Cow Lineup》 #单调队列# #离散化# #队列# #双指针,two-pointer# #USACO# #2011#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

// 奶牛结构体,存储位置和品种
struct cow 
{
    int pos, type;
} a[50005];  // 存储所有奶牛信息

int n, m, head, x, ans = 2e9;  // n: 奶牛数量, m: 品种数, head: 滑动窗口左边界
                                // x: 当前窗口包含的品种数, ans: 最小覆盖区间长度
map<int, int> s;  // 记录各品种在窗口中的出现次数

// 比较函数:按位置升序排序
bool cmp(cow x, cow y)
{
    return x.pos < y.pos;
}

int main()
{
    // 输入奶牛数量
    cin >> n;
    
    // 输入每头奶牛的位置和品种,并记录品种
    for (int i = 0; i < n; i++) 
    {
        cin >> a[i].pos >> a[i].type;
        s[a[i].type] = 1;  // 标记该品种存在
    }
    
    m = s.size();  // 计算不同品种的总数
    
    // 按位置排序奶牛
    sort(a, a + n, cmp);
    
    // 滑动窗口算法寻找最小覆盖区间
    for (int i = 0; i < n; i++) 
    {
        s[a[i].type]++;  // 当前品种计数增加
        
        // 如果该品种首次在窗口中出现两次,增加x
        if (s[a[i].type] == 2) 
        {
            x++;
        }
        
        // 当窗口包含所有品种时,尝试收缩左边界
        while (x == m) 
        {
            // 更新最小区间长度
            ans = min(a[i].pos - a[head].pos, ans);
            
            // 左边界移动,对应品种计数减少
            s[a[head].type]--;
            
            // 如果某个品种不再满足覆盖条件,减少x
            if (s[a[head].type] == 1) 
            {
                x--;
            }
            head++;  // 移动左边界
        }
    }
    
    // 输出结果
    cout << ans;
    
    return 0;
}

【运行结果】

6 
25 7
26 1
15 1
22 3
20 1
30 1
4
posted @ 2026-02-18 21:17  团爸讲算法  阅读(5)  评论(0)    收藏  举报