Cpp环境【POJ3320】Jessica's Reading Problem 洁西卡的复习计划

Description  【问题描述】

Jessica’s a very lovely girl wooed by lots of boys. Recently she has a problem. The final exam is coming, yet she has spent little time on it. If she wants to pass it, she has to master all ideas included in a very thick text book. The author of that text book, like other authors, is extremely fussy about the ideas, thus some ideas are covered more than once. Jessica think if she managed to read each idea at least once, she can pass the exam. She decides to read only one contiguous part of the book which contains all ideas covered by the entire book. And of course, the sub-book should be as thin as possible.
A very hard-working boy had manually indexed for her each page of Jessica’s text-book with what idea each page is about and thus made a big progress for his courtship. Here you come in to save your skin: given the index, help Jessica decide which contiguous part she should read. For convenience, each idea has been coded with an ID, which is a non-negative integer.


  (省略无数无关词)为准备考试,Jessica开始阅读一本很厚的课本。要想通过考试,她必须把课本中所有知识点都掌握。这本书总共有P页,第i页恰好有一个知识点a[i](每个知识点都有一个整数编号)。全书中同一个知识点可能会被多次提到,所以她希望通过阅读其中连续的一些页把所有的知识点都覆盖到。给定每页写到的知识点,请求出要阅读的最少页数。

Input  【输入格式】

The first line of input is an integer P (1 ≤ P ≤ 1000000), which is the number of pages of Jessica’s text-book. The second line contains P non-negative integers describing what idea each page is about. The first integer is what the first page is about, the second integer is what the second page is about, and so on. You may assume all integers that appear can fit well in the signed 32-bit integer type.


  第一行一个整数P,表示书本的总页数。接下来的一行,包含P个整数,第i整数表示第i页包含的知识点的编号。

Output  【输出格式】

Output one line: the number of pages of the shortest contiguous part of the book which contains all ideals covered in the book.


  一个整数,表示需要阅读的最少连续页数

Sample Input  【输入样例】

5
1 8 8 8 1

Sample Output  【输出样例】

2

【数据范围】  

1<=P<=10^6 , 1<=a[i]<=10^9

【来源】

POJ3320

【思路梳理】

  一个变形后的滑动窗口应用问题,要求的是滑动窗口的最小长度,使得在这个滑动窗口内有全集中的任意一个元素。显然滑动窗口在长度最小且满足该条件时,每个元素可能有多个。
  首先考虑存储的容器。因为需要对每个元素——知识点的序号的种类数进行统计,而这个序号可能会很大(高达10的9次方),显然用map映射(“超级数组”)来存储比较稳妥,将无序的知识点的序号映射到该序号在滑动窗口中出现的次数。
  在滑动窗口的元素种类数小鱼总的知识点数的时候,只需要把这一页所对应的知识点进map就可以,若该页对应的知识点为i,那么map[a[i]]++。
  当滑动窗口中的元素的种类数等于总的知识点数的时候,我们就检查能否缩短滑动窗口的长度(用s和d分别标记滑动窗口的起点和终点),即map[a[s]]是否大于1,如果为真就说明滑动窗口可以右移并且重复此判断,若否就停止。对于每一个时刻我们都用一个ans来取一个最小的滑动窗口长度(length=d-s+1)即可。
  这个题的数据最后两组非常大,一定要把各种优化加上!
【Cpp代码】

#include
#include
#define inf 2000000005
#define maxn 1000005
using namespace std;
int tot,p,ans=inf,a[maxn];
map<int,int>mp;

int read()//手工读入防止超时
{
    char ch=getchar();bool ok=false;int cnt=0;
    while((ch<'0' || ch>'9') && ch!='-')    ch=getchar();   
    while((ch>='0' && ch<='9') || ch=='-')
    {
        if(ch=='-') ok=true;
        else cnt=cnt*10+ch-'0';
        ch=getchar();
    }
    return ok? -cnt:cnt;
}
int min(int a,int b){if(a>b)return b;return a;}

void solve()
{
    mp.clear();
    int num=0,s=1;
    for(int i=1;i<=p;i++)//滑动窗口的终点为i,起点为s
    {
        mp[a[i]]++;//进滑动窗口
        if(mp.size()continue;//滑动窗口中元素种类数没有达到总的知识点个数
        if(a[i]==a[s])  mp[a[i]]--,s++;//起点和终点相同,直接把起点往右侧挪
        while(mp[a[s]]>1 && s!=i)//若起点页码对应的知识点出现多次,那么就可以不断把起点往右移
        {           
            mp[a[s]]--;
            s++;
        }
        ans=min(ans,i-s+1);//记录最小长度
    }
    printf("%d",ans);
}

int main()
{
//  freopen("input10.txt","r",stdin);
    p=read();   
    for(int i=1;i<=p;i++)   { a[i]=read();mp[a[i]]++; }
    tot=mp.size();
    solve();
    return 0;
}

你可能感兴趣的:(cpp,poj,滑动窗口,基础算法之一,查找搜索&排序,算法科技之滑动窗口,难度评级,Time,Required)