您的位置:首页 > 其它

动态规划5:求解最多航线问题(应用了最长子序列知识)

2014-09-11 12:14 337 查看




这道题应用了动态规划的相关的知识来解决,主要是应用到了最长上升子序列的知识来解决,下面引述动态规划32讲中的相关解释来解决该问题:

 

【问题分析】

这道题目相对来说思考难度较高,从字面意义上看不出问题的本质来,有点无法下手的感觉。

这里我给大家推荐两种思考这类问题的方法。

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

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

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

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    C2

D1    D2

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

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

N=3

C1    C2     C3

D1    D2     D3

……

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

对于任意两条航线如果满足 Ci<Cj  且Di<Dj  则两条航线不相交。这样的话要想在一个序列里

让所有的航线都不相交那比然满足, C1<C2<C3…Cans 且 D1<D2<D3…<Dans  ,也就是将 C 排

序后求出最长的满足这个条件的序列的长度就是解。

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

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

总复杂度为 O(n2).

CODE:
//2014年9月11日11:53:19
//author:BGY
#include<stdio.h>
#include<climits>
#include<algorithm>
#include<stack>
#include<iostream>
#include<cmath>
#include<set>
#include<vector>
#include<map>
#include<queue>
#include<string.h>
using namespace std;
const int maxn=6500;
typedef struct node
{
int north;
int south;
}node;
int cmp(node a, node b)
{
return a.north<b.north;
}
node a[maxn];
int opt[maxn];
int main(void)
{
int n,m;
while(scanf("%d %d",&n,&m)!=EOF)
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
scanf("%d %d",&a[i].north,&a[i].south);
}
sort(a+1,a+t+1,cmp);//把他们按照北岸的那个点的顺序来排列;
a[0].north=INT_MIN;
a[0].south=INT_MIN;//初始化第一个为最小的
memset(opt,0,sizeof(opt));//最小化
for(int i=1;i<=t;i++)
{
for(int j=0;j<i;j++)
{
if(a[i].south>a[j].south&&opt[i]<opt[j]+1)
{
opt[i]=opt[j]+1;
}
}
}//求出opt
int c=INT_MIN;
//找出最大的那个,就是说明了他必须具备的性质
for(int i=1;i<=t;i++)
{
if(opt[i]>c) c=opt[i];
}
cout<<c<<endl;
}
return 0;
}


COME ON
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: