2005年百度之星程序设计大赛初赛试题与解答 第2题 动态规划解法

/***********************************************************************************************

题目描述:请编写程序,找出下面 “ 输入数据及格式 ” 中所描述的输入数据文件中最大重叠区间的大小。

对一个正整数 n ,如果 n 在数据文件中某行的两个正整数(假设为 A 和 B )之间,即 A<=n<=B 或 A>=n>=B ,则 n 属于该行;如果 n 同时属于行 i 和 j ,则 i 和 j 有重叠区间;重叠区间的大小是同时属于行 i 和 j 的整数个数。
例如,行( 10 20 )和( 12 25 )的重叠区间为 [12 20] ,其大小为 9 ;行( 20 10 )和( 12 18 )的重叠区间为 [10 12] ,其大小为 3 ;行 (20 10) 和( 20 30 )的重叠区间大小为 1 。

输入数据:程序读入已被命名为 input.txt 的输入数据文本文件,该文件的行数在 1 到 1,000,000 之间,每行有用一个空格分隔的 2 个正整数,这 2 个正整数的大小次序随机,每个数都在 1 和 2^32-1 之间。(为便于调试,您可下载测试 input.txt 文件,实际运行时我们会使用不同内容的输入文件。)

输出数据:在标准输出上打印出输入数据文件中最大重叠区间的大小,如果所有行都没有重叠区间,则输出 0 。

评分标准:程序输出结果必须正确,内存使用必须不超过 256MB ,程序的执行时间越快越好。
 */


/***********************************************************************************************
思路描述:动态规划,数组leftarr[i][j]描述的是,左端点小于等于leftarr[i][0]的所有线段中,
右端点的最大值为leftarr[i][1]。对于线段(left,right),二分法找i,使得leftarr[i][0]是比left小的最大数,
计算最大线段值,修改leftarr[i][1];如果需要,删除leftarr[j](j>i)后面的线段。
算法的时间复杂度也是O(NlogN),N为线段个数。但由于删除冗余的线段,总体时间比普通的排序再比较的算法要快,
测试发现快40%(见结果比较)。空间复杂度为线段个数。
**************************************************************************************/


/***********************************************************************************************

源代码,包括三部分:自己算法代码,他人算法的源代码,比较两者效率的源代码 (c++, 通过eclipse+CDT+MinGW编译):
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <fstream>
#include <stdlib.h>
#include "time.h"

using namespace std;

#define max(x, y)((x)<(y))? (y): (x)
#define min(x, y)((x)<(y))? (x): (y)


class BStarMaxInterSeg
{
    //(left,所有左端点比left小的线段中,最大的的右端点值)
    map<unsigned int, unsigned int> leftarr;
    unsigned maxseg;
public:
    int addseg(unsigned int segleft, unsigned int segright);
    unsigned int getmaxseg();
    BStarMaxInterSeg();
    int clear();
};

BStarMaxInterSeg::BStarMaxInterSeg(){maxseg=0;}

int BStarMaxInterSeg::clear(){maxseg=0;leftarr.clear();return 1;}

unsigned int BStarMaxInterSeg::getmaxseg(){return maxseg;}

int BStarMaxInterSeg::addseg(unsigned int segleft, unsigned int segright){
    map<unsigned int, unsigned int>::iterator cur;
    map<unsigned int, unsigned int>::iterator last;//在cur之后,右端点比cur大的第一个节点
    unsigned int go;

    if(((segright-segleft)+1)<=maxseg) return 1;

    go=0;
    cur=leftarr.find(segleft);
    if(cur!=leftarr.end()){
        if (cur->second > segright)
            maxseg=max(maxseg, (segright-segleft)+1);
        else {
            maxseg=max(maxseg, (cur->second-segleft)+1);
            cur->second=segright;
            go=1;
        }
    }
    else{
        maxseg=max(maxseg, (segright-segleft)+1);
        leftarr.insert(pair<unsigned int, unsigned int>(segleft,segright));
        cur=leftarr.find(segleft);
        if(cur!=leftarr.begin()) {
            cur--;
            if(cur->second > segright) {
                maxseg=max(maxseg, (segright-segleft)+1);
                cur++;
                leftarr.erase(cur);
            }
            else {
                if(cur->second>segleft)
                    maxseg=max(maxseg, (cur->second-segleft)+1);
                cur++;
                go=1;
            }
        }
        else go=1;
    }

    if(go==1){
        last=cur;
        last++;
        while(last!=leftarr.end()){
            if(last->second < cur->second)
                maxseg=max(maxseg, (last->second - last->first)+1);
            else {
                if(cur->second>last->first)
                    maxseg=max(maxseg, (cur->second - last->first)+1);
                break;
            }
            last++;
        }
        if(last==leftarr.end()) last--;
        if(last!=cur) last--;
        if(last!=cur){
            cur++;
            leftarr.erase(cur,last);
        }
    }
    return 1;
}


/*********************************************test****************************************************/
//来源http://www.cnblogs.com/kaikai/archive/2005/09/21/241452.html
int cmp(const void *a, const void *b)
{
    return *(unsigned int*)a > *(unsigned int*)b;
}
inline unsigned int cover(unsigned int n[2], unsigned int e)
{
    unsigned int left = n[0];
    unsigned int right = min(n[1], e);
    if (left <= right)
        return right - left + 1;
    return 0;
}

class BStarMaxInterSeg_test{
    unsigned int map[1000000][2];
    unsigned num;
public:
    unsigned int add(unsigned int x, unsigned int y);
    unsigned int getmax();
    BStarMaxInterSeg_test();

};

BStarMaxInterSeg_test::BStarMaxInterSeg_test(){num=0;}

unsigned int BStarMaxInterSeg_test::add(unsigned int x, unsigned int y){
    map[num][0] = x;
    map[num][1] = y;
    num++;
    return num;
}

unsigned int BStarMaxInterSeg_test::getmax(){

    unsigned int i = 0;
    unsigned int end;
    unsigned int maxcover = 0, c;

    qsort(map, num, sizeof(int)*2, cmp);
    end = map[0][1];
    for (i = 1; i < num; i++)
    {
        c = cover(map[i], end);
        if (c > maxcover)
            maxcover = c;

        if (map[i][1] > end)
        {
            end = map[i][1];
        }
    }

    return maxcover;
}


/*************************************compare*********************************************************/
int doit(){
    unsigned const int maxnum=1000000;
    unsigned int num, x,y,t,i,tt;

    BStarMaxInterSeg* a;
    BStarMaxInterSeg_test* b;
    srand(time(0));
    clock_t start,finish;
    double totaltime;

    for(tt=0;tt<10;tt++){
        start=clock();
        for(i=1;i<10;i++){
            a=new BStarMaxInterSeg();
            for(num=0;num<maxnum;num++){
                x=(unsigned int)(rand());
                y=(unsigned int)(rand());
                if(x>y) {t=x;x=y;y=t;}
                a->addseg(x,y);
            }
            a->getmaxseg();
            delete a;
        }


        finish=clock();
        totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
        cout<<"my time:"<<totaltime<<endl;

        start=clock();
        for(i=1;i<10;i++){
            b=new BStarMaxInterSeg_test();
            for(num=0;num<maxnum;num++){
                x=(unsigned int)(rand());
                y=(unsigned int)(rand());
                if(x>y) {t=x;x=y;y=t;}
                b->add(x,y);
            }
            b->getmax();
            delete b;
        }

        finish=clock();
        totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
        cout<<"test time:"<<totaltime<<endl;
        cout<<endl;
    }
    return 1;
}
**************************************************************************************/




/***********************************************************************************************
两种算法效率比较:
my time:0.61
test time:0.984

my time:0.593
test time:1.016

my time:0.625
test time:0.969

my time:0.625
test time:0.922

my time:0.61
test time:0.969

my time:0.609
test time:0.891

my time:0.625
test time:0.968

my time:0.609
test time:0.954

my time:0.625
test time:0.937

my time:0.609
test time:0.938
**************************************************************************************/

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值