摆渡线路【区间DP】
问题描述:
某市的 M 公园中有一个近乎圆形的湖,有100 个主要景点分布在湖边,为了方便游客,公园在一些景点之间开设了直通的摩托飞艇摆渡的项目一来减少游客在景点到景点之间所花的时间,二来也可以让游客体验一下惊险刺激的摩托飞艇。果然摩托飞艇摆渡项目大为12..成功,为了充分满足游客需要,摆渡线路越来越多。不料随着线路的增加,危险性也随之增加。如果两个摆渡线路之间有交叉(如上图),在这两个线路上的飞艇一旦发生碰撞,后果将不堪设想。公园的管理层近日做出决定,本着安全第一的原则,在这个湖上取消一些线路,使剩下的任意两条线路在行驶阶段(即不考虑码头)不交叉。同时,考虑到经济效益,他们要求被取消的线路数最小,即保留尽量多的线路。他们希望你能够帮助他们算一算最多可以保留多少条线路。
数据输入:
第一行为 N(1=<N<=10000),表示现有的线路数。接下来的 N 行,每行有两个 1 至 100 的数 a,b,表示 a 至 b 之间有飞艇往返。显然 a 不会等于 b,且若 a 至 b 有线路,则 b 至 a 也必有线路,它们不会同时出现在输入文件中。
数据输出:
只有一行,只有一个数,就是保留下来的线路的最多条数。
输入输出样例:
line.in
5
91 31
1 45
27 5
11 65
43 72
line.out
3
简化题目:
一个圆,圆上有100个点,N条弦,让你选择尽量多互不相交的弦
思路:
把圆展开成链,然后“倍长”
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示第
i
i
i 个位置到第
j
j
j 个位置的所选弦的最多数量
那么我们可以枚举一个中间点
k
k
k,然后进行区间DP(和Floyed有异曲同工之妙)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#define r register
#define rep(i,x,y) for(r ll i=x;i<=y;++i)
#define per(i,x,y) for(r ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
ll n,dp[500][500],x,y,a[500][500],ans;
int main()
{
//freopen("line.in","r",stdin);
//freopen("line.out","w",stdout);
scanf("%lld",&n);
rep(i,1,n)
{
scanf("%lld%lld",&x,&y);
if(x>y) swap(x,y);
a[x][y]=a[x+100][y+100]=1;
}
rep(t,2,100)
rep(i,1,200-t+1)
{
ll j=i+t-1;
rep(k,i,j)
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k][j]);
dp[i][j]+=a[i][j];
}
rep(i,1,100)
ans=max(ans,dp[i][i+99]);
cout<<ans;
return 0;
}