【问题描述】
某国家被一条河划分为南北两部分,在南岸和北岸总共有N对城市,每一城市在对岸都有唯一的友好城市,任何两个城市都没有相同的友好城市。每一对友好城市都希望有一条航线来往,于是他们向政府提出了申请。由于河终年有雾。政府决定允许开通的航线就互不交叉(如果两条航线交叉,将有很大机会撞船)。兴建哪些航线以使在安全条件下有最多航线可以被开通。
【输入格式】
输入文件(ship.in):包括了若干组数据,每组数据格式如下:
     第一行两个由空格分隔的整数x,y,10〈=x〈=6000,10〈=y〈=100。x表示河的长度而y表示宽。第二行是一个整数N(1<=N<=5000),表示分布在河两岸的城市对数。接下来的N行每行有两个由空格分隔的正数C,D(C、D〈=x〉,描述每一对友好城市与河起点的距离,C表示北岸城市的距离而D表示南岸城市的距离。在河的同一边,任何两个城市的位置都是不同的。
【输出格式】
输出文件(ship.out):要在连续的若干行里给出每一组数据在安全条件下能够开通的最大航线数目。
【输入输出样例】

Ship.in

30   4

5

4   5

2   4

5   2

1   3

3   1

Ship.out

3

【问题分析】

这道题目相对来说思考难度较高,从字面意义上看不出问题的本质来,有点无法下手的感觉。这里我给大家推荐两种思考这类问题的方法。

法一:寻找规律法(我前面总结提到的第3个方法)

寻找规律自然要推几组数据,首先当然有从样例入手;

动态规划入门5

仔细观察上图:红色航线是合法的,那么他们满足什么规律呢?

C1 C2 C3 C4

北岸红线的端点: 4 9 15 17

南岸红线的端点: 2 8 12 17

D1 D2 D3 D4

不难看出无论线的斜率如何,都有这样的规律:

C1<C2<C3<C4 D1<D2<D3<D4

如果我们把输入数据排升序,问题变抽象为:

在一个序列(D)里找到最长的序列满足DI<DJ<Dk……且i<j<k

这样的话便是典型的最长非降子序列问题了。。。。

法二:边界条件法(我前面总结提到的第4个方法)

边界法其实就是把数据往小了缩,显然N=1是答案是1。N=2时呢?

考虑这样一组数据:

N=2

C1 D1

C2 D2

当 C1<C2 时,如果D1>D2 那么一定会相交,反之则不会相交。

当C1 >C2时,如果D1<D2 那么一定会相交,反之则不会相交。

N=3

C1 D1

C2 D2

C3 D3

……

其实不用在推导N=3了,有兴趣的可以推导去。看N=2时就能得出:

对于任意两条航线如果满足Ci<Cj 且Di<Dj 则两条航线不相交。这样的话要想在一个序列里让所有的航线都不相交那比然满足,C1<C2<C3…Cans且D1<D2<D3…<Dans ,也就是将C排序后求出最长的满足这个条件的序列的长度就是解。

这样分析后显然是一个最长非降子序列问题。

复杂度:排序可以用O(nlogn)的算法,求最长非降子序列时间复杂度是O(n2).

总复杂度为O(n2).

【源代码】

//By LYLtim

type node=record c,d,l:word; end;

var x,n:word;
    y:byte;
    a:array[1..5000]of node;
    maxl:word;

procedure init;
var i:word;
begin
    assign(input,'ship.in');reset(input);
    readln(x,y);
    readln(n);
    for i:=1 to n do
        with a[i] do
            begin
                readln(c,d);
                l:=1;
            end;
    close(input);
end;{init}

procedure qsort(l,r:word);
var pl,pr,m:word;
    t:node;
begin
    pl:=l;pr:=r;m:=a[(l+r)>>1].c;
    repeat
        while a[pl].c<m do inc(pl);
        while a[pr].c>m do dec(pr);
        if pl<=pr then
            begin
                t:=a[pl];a[pl]:=a[pr];a[pr]:=t;
                inc(pl);dec(pr);
            end;
    until pl>pr;
    if pl<r then qsort(pl,r);
    if pr>l then qsort(l,pr);
end;{qsort}

procedure work;
var i,j:word;
begin
    for i:=2 to n do
        begin
            for j:=1 to i-1 do
                if(a[j].d<a[i].d)and(a[j].l+1>a[i].l)then a[i].l:=a[j].l+1;
            if a[i].l>maxl then maxl:=a[i].l;
        end;
end;{work}

procedure print;
begin
    assign(output,'ship.out');rewrite(output);
    writeln(maxl);
    close(output);
end;{print}

begin{main}
    init;
    qsort(1,n);
    work;
    print;
end.

posted on 2011-08-05 10:53  shallyzhang  阅读(457)  评论(0)    收藏  举报