USACO 2011 November Cow Lineup /// map set 尺取法 oj25279

题目大意:

输入n 接下来n行描述n头牛的编号num和品种id

得到包含所有id的最短段 输出最短段的编号差

Sample Input

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

Sample Output

4

Hint

INPUT DETAILS:

There are 6 cows, at positions 25,26,15,22,20,30, with respective breed IDs 7,1,1,3,1,1.

OUTPUT DETAILS:

The range from x=22 up through x=26 (of total size 4) contains each of the distinct breed IDs 1, 3, and 7 represented in FJ's herd.

 

有思路而不会代码实现也是够痛苦

将牛按num排序后

15 20 22 25 26 30

1   1    3   7   1   1

将15为段头 直到段尾为25时符合要求出现了所有id

但 id 1 出现过两次 所以可以缩小该段 将段头移向下一位20

此时为符合要求的最小段 保存当前段的编号差

将段头移向下一位 继续移动段尾

直到符合要求进行判断 更新保存最小的编号差

#include <bits/stdc++.h>
using namespace std;
struct Cow{ int num,id; }cow[50005]; 
map <int,int> m; /// 记录id出现的次数
set <int> id_set; /// 记录出现过的品种id 得到一共有多少种品种
bool cmp(Cow q,Cow p)
{
    return q.num<p.num; 
} /// 结构体按编号num排序 不会重复所以不需考虑相等
int main()
{
    /// num_map为符合要求的一段的该段当前id数 
    /// num_id为该队中的所有id数
    /// head tail为当前该段的段头和段尾
    int n,num_id,num_map,head,tail,mini;
    while(~scanf("%d",&n))
    {
        id_set.clear(); m.clear();
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&cow[i].num,&cow[i].id);
            m[cow[i].id]=0; id_set.insert(cow[i].id);
        }
        sort(cow,cow+n,cmp);

        num_id=id_set.size();  /// set可以去重 即所有id数
        head=tail=num_map=0;  
        mini=0x3f3f3f3f;

//        for(int i=1;i<=n;i++)
//            printf("%d %d\n",cow[i].num,cow[i].id);
//        printf("\n");

        while(1)
        {
            while(num_map!=num_id && tail<n)
            {
                if(m[cow[tail].id]==0) num_map++; 
                m[cow[tail++].id]++;
                /// 如果此id没出现过则该段当前id数+1
                /// m记录该段id出现次数
            } /// 持续记录id,直到该段当前id数为所有id数 或 已到队尾

            if(tail==n && num_map!=num_id) break;
            /// 已到队尾 且 不存在符合要求的组合 则跳出

            while(m[cow[head].id ]>1)
                m[cow[head++].id ]--; 
            /// 当前id数 为 所有id数 若段头的id在该段中出现次数>1
            /// 则可缩小该段长度 段头可移到下一位
            /// 如 13312 这种情况可缩小该段长度到 312

            mini=min(mini,cow[tail-1].num-cow[head].num);

            m[cow[head++].id]--; num_map--;
            /// 继续遍历后面有无符合要求的组合 
            /// 段头移到下一位 该段中当前id数-1
        }
        printf("%d\n",mini);
    }

    return 0;
}
/*
6
25 7
26 1
15 1
22 3
20 1
30 1
*/
View Code

 ...原来这是尺取法

再加种写法 ...虽然差不多

        while(head<=tail&&tail<=n)
        {
            if(num_map<num_id)
            {
                if(m[cow[tail].id]==0) num_map++;
                m[cow[tail++].id]++;
            }
            else if(num_map==num_id)
            {
                while(m[cow[head].id]>1)
                    m[cow[head++].id]--;
                mini=min(mini,cow[tail-1].num-cow[head].num);
                m[cow[head++].id]--; num_map--;
            }
        }    
View Code

 

posted @ 2018-03-16 17:15  _Jessie  阅读(257)  评论(0编辑  收藏  举报