| 题目链接 | 难度等级 | 完成状态 | 完成分数 | 最后编辑时间 | 失误原因(初次提交分数) |
|---|---|---|---|---|---|
| 线段覆盖 2 | ★☆☆☆☆ | 答案正确 | 100 | 2014/11/26 21:52:22 | 40(超时) |
数轴上n条线段,各有价值,挑出若干,使两两不覆盖且价值之和最大。
首先先把点离散化掉(原数据排序,然后从大到小分别对应到1、2、3…),然后DP方程很容易想到:
f[st][st+len]=max{f[st][st+slen]+f[st+slen][st+len]};//f[i][j]表示从第i个离散化的点到第j个点的最大价值
这是O()的算法,会TLE。然后进一步优化,和石子归并等区间题不同的是,我们可以发现非从头开始的f都是没有意义的(这是序列动态规划和区间动态规划的区别),所以把st固定为1,得到:
f[len]=max(f[len],f[slen]+a[slen][len]);//f[i]表示从头到第i个点的最大价值
详见代码。
| 3027.cpp代码已折叠
展开折叠内容
|
|---|
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int pointsDced[1000001]={},f[3000],a[3000][3000],idTotal=0,n,points[3001]={-1},pointsSize=0,lhs[3001],rhs[3001],value[3001];
void discrete()
{
sort(points+1,points+pointsSize+1);
for(int i=1;i<=pointsSize;++i)
{
if(points[i]==points[i-1])
continue;
pointsDced[points[i]]=++idTotal;
}
}
void init()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d%d%d",&lhs[i],&rhs[i],&value[i]);
points[++pointsSize]=lhs[i];
points[++pointsSize]=rhs[i];
}
discrete();
for(int i=1;i<=n;++i)
a[pointsDced[lhs[i]]][pointsDced[rhs[i]]]=value[i];
}
void DP()
{
for(int len=1;len<=idTotal;++len)//错误修复:<=n -> <=idTotal
for(int slen=1;slen<len;++slen)
f[len]=max(f[len],f[slen]+a[slen][len]);
}
int main()
{
init();
DP();
cout<<f[idTotal]<<endl;
}
|