【poj3320】Jessica's reading problem,解题报告+数据+代码

5 篇文章 0 订阅
1 篇文章 0 订阅
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <map>
#include <iostream>
/*
    Problem : POJ3320-Jessica's reading problem;
    Begin Time: 27/2/2012 5:30 p.m.
    End Time:   29/2/2012 11:13 a.m
    Last Time: 2Days+
    Test Data:
1
1
1
100000
6
1 1 1 1 1 1
5
1 8 8 8 1
6
1 2 3 4 5 6
5
1 2 3 4 4
8
1 2 3 3 3 4 5 6
10
1 2 2 2 4 2 5 2 2 2
18
1 2 3 3 3 3 2 1 1 1 1 2 2 2 2 2 3 3
5
1 2 2 3 1

5
1 2 2 2 1

5
1 2 2 2 2

6
1 2 3 2 3 1

9
1 2 3 4 5 4 3 2 1

10

1 2 7 9 10 7 10 3 2 1

11

1 1 2 6 8 5 6 6 6 6 6
    State:
9862066	lyx5398	3320	Accepted	1104K	344MS	C++	1506B	2012-02-29 10:46:48
    思路:
    感谢
    http://hi.baidu.com/rain_bow_joy/blog/item/bf3e3acbda80c88cc9176811.html
    这份解题报告!

    把ideas按照出现的顺序编号,比如
    1 8 3 3 3 3 5 1
    那么1的编号就是1,8的编号就是2,3的编号就是3,5的编号就是4
    以下所称的“idea个数”均指编号后的idea的个数,比如上例中
    idea个数 = 4
    编号存放在nums_id里
    然后从第一个元素开始搜索
    搜索时,判断当前元素是否在搜索的这个子序列(从0到i)未出现过
    如果是,那么该编号(nums_id[i])的元素的最右点的值为当前的i
            并且现在已找到的idea个数++,如果与总的idea个数相等
            那么取出目前找到的所有idea的最右点的值中最小的。
            木桶原理,记得么,亲,只有最左边的值被算在里面
            我们才能保证这个区间覆盖了所有元素。
            len = i - *tmp + 1;
            然后我们把最左边的元素丢弃,*tmp = 0;num--,继续寻找
    如果否,那么仅仅刷新该编号的p[nums_id[i]) = i;就可以了

    核心算法伪代码如下:
    for(int i = 0  ; i <=n; i++)
    if(p[nums_id[i]]==0)
        p[nums_id[i]] = i;
        now_num++;
        if(now_num == total)
            计算当前区间的最短长度
            int* tmp = min_element(p[1],p[total+1]);
        if(len < min) min = len;
        *tmp = 0;now_num--;
    else
        p[nums_id[i]] = i;
    至于这道题的意思
    就是在[0,n]这个区间内找一个最短的区间,使得这个最短区间包含[0,n]的所有
    idea,所以我们只要找到[0,n]中所有 包含所有idea 的区间,然后取其长度最短的
    就可以了
*/
//#define INPUT
using namespace std;
const int MAX_SIZE  = 1100000;
int total; //出现的元素总数
int lmin = INT_MAX/2; //区间最小长度
int p[MAX_SIZE];//每个idea到达的最大点
//int num_id[MAX_SIZE]; //每个idea经过压缩后的编号
int nums[MAX_SIZE];  //存储的压缩、编号过得ideas
int main(int argc,char* argv[])
{
    int n;
    int j;
#ifdef INPUT
    freopen("b:\\acm\\poj3320\\input.txt","r",stdin);
#endif
    map<int,int> num_id;
    scanf("%d",&n);
    for(int i = 1 ; i <= n ; i ++)
    {
        scanf("%d",&j);
        if(num_id[j] == 0)
        {
            total++;
            num_id[j] = total; ///离散化必须用map,不知道为甚。。。
        }
        nums[i] = num_id[j];
    }
/**********SOLVE THE PROBLEM ******
///nums的数据大小(比如说可能有数字大于MAX_SIZE)可能出错,需要注意
///
    int now_num = 0; ///当前搜索到的idea个数(不包括重复的)
    int len = 0; ///当前计算的区间长度
    int *tmp; ///指向区间左端点的指针
    for(int i = 1 ; i <= n ; i++)
    {
        if( p[nums[i]] == 0)
        {
            now_num++;
            p[nums[i]] = i;
            if( now_num == total)
            {
                tmp = min_element(&p[1],&p[total+1]);
                len = i - *tmp + 1;
                if( len < lmin)
                    lmin = len;
                now_num--;
                *tmp = 0;
            }
        }
        else
        {
            p[nums[i]] = i;
        }
    }
    printf("%d\n",lmin);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值