【codevs】线段覆盖系列 贪心&&动规
2015-10-09 18:40
399 查看
线段覆盖
贪心,不说了。代码:
[code]#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int size=1000010; struct edge{ int l,r; }l[size]; bool cmp(const edge &a,const edge &b) { return a.r<b.r; } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&l[i].l,&l[i].r); if(l[i].l>l[i].r) swap(l[i].l,l[i].r); } sort(l+1,l+1+n,cmp); int ans=0; for(int i=1,last=-2333;i<=n;i++) { if(last<=l[i].l) { last=l[i].r; ans++; } } printf("%d",ans); return 0; }
线段覆盖2
这个是dp。按右端点排序。
dp[i]代表当第i个线段是被选择的最后一个线段后,所达到的最大价值。
所以状态转移方程:
[code]dp[i]=max{dp[i],dp[j]+l[i].d} (j<i && l[i].l>=l[j].r)
代码:
[code]#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int size=23333; int dp[size]; struct edge{ int l,r,d; }l[size]; bool cmp(const edge &a,const edge &b) { return a.r<b.r; } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d%d",&l[i].l,&l[i].r,&l[i].d); sort(l+1,l+1+n,cmp); int ans=0; for(int i=1;i<=n;i++) { dp[i]=l[i].d; for(int j=1;j<i;j++) { if(l[j].r<=l[i].l) { dp[i]=max(dp[i],dp[j]+l[i].d); } } ans=max(dp[i],ans); } printf("%d",ans); return 0; } /* 10 7 8 1 1 7 2 0 3 3 4 9 4 0 6 5 5 7 6 0 3 7 7 8 8 7 10 9 4 7 10 */
线段覆盖3
贪心,和第一个一样。线段覆盖4
这个也是dp,不过n太大,不能n^2。可以改变状态的表示。
dp[i]代表选到坐标i的时候所拿到的最大价值。
状态转移方程:
[code]dp[i]=max{ dp[i],max{ dp[1],dp[2],...,dp[i-1] }+l[i].d }
但因为是线段,所以可以这样:
[code]dp[l[i].r]=max{ dp[i],max{dp[1],dp[2]...,dp[l[i].l]}+l[i].d }
因为要先确定
dp[l[i].l],所以应该把坐标按左端点排序。
如何选取
1~l[i].l的最大值?
树状数组!
这样就优化到O(nlogn)
代码:
[code]#include<cstring> #include<iostream> #include<cstdio> #include<algorithm> using namespace std; typedef long long LL; const LL size=1000010; const LL INF=(LL)1e15; struct edge{ LL l,r; LL d; }l[size]; LL dp[size]; bool cmp(const edge &a,const edge &b) { return a.l<b.l; } LL bits[size]; void add(LL x,LL d) { for(LL i=x;i<=size-10;i+=i&(-i)) { bits[i]=max(bits[i],d); } } LL ask(LL x) { LL ans=0; for(LL i=x;i>0;i-=i&(-i)) { ans=max(ans,bits[i]); } return ans; } int main() { LL n; scanf("%lld",&n); for(LL i=1;i<=n;i++) scanf("%lld%lld%lld",&l[i].l,&l[i].r,&l[i].d); sort(l+1,l+1+n,cmp); LL ans=0; for(LL i=1;i<=n;i++) { dp[l[i].r]=max(dp[l[i].r],ask(l[i].l)+l[i].d); ans=max(ans,dp[l[i].r]); add(l[i].r,dp[l[i].r]); } printf("%lld",ans); return 0; }
线段覆盖5
坐标离散化,就和4一样了。听说卡P党?
代码:
[code]#include<cstring> #include<iostream> #include<cstdio> #include<algorithm> using namespace std; typedef long long LL; const LL size=2000010; const LL INF=(LL)1e15; struct edge{ LL l,r; LL d; }l[size]; bool cmp(const edge &a,const edge &b) { return a.l<b.l; } LL lsh[size]; LL dp[size],bits[size]; void add(LL x,LL d) { for(LL i=x;i<=size-10;i+=i&-i) { bits[i]=max(bits[i],d); } } LL ask(LL x) { LL ans=0; for(LL i=x;i>0;i-=i&-i) { ans=max(bits[i],ans); } return ans; } int main() { LL n; scanf("%lld",&n); for(LL i=1;i<=n;i++) { scanf("%lld%lld%lld",&l[i].l,&l[i].r,&l[i].d); lsh[++lsh[0]]=l[i].l; lsh[++lsh[0]]=l[i].r; } sort(lsh+1,lsh+1+lsh[0]); LL len=unique(lsh+1,lsh+1+lsh[0])-lsh-1; for(LL i=1;i<=n;i++) { l[i].l=lower_bound(lsh+1,lsh+1+len,l[i].l)-lsh; l[i].r=lower_bound(lsh+1,lsh+1+len,l[i].r)-lsh; } //for(LL i=1;i<=n;i++) printf("%d %d %d\n",l[i].l,l[i].r,l[i].d); sort(l+1,l+1+n,cmp); LL ans=0; for(LL i=1;i<=n;i++) { dp[l[i].r]=max(dp[l[i].r],l[i].d+ask(l[i].l)); ans=max(ans,dp[l[i].r]); add(l[i].r,dp[l[i].r]); } printf("%lld",ans); return 0; } /* 5 233 2333 1 100 1000 2 123 321 3 444 555 4 12 450 5 */
总结:序列型动规应该是比较简单的,但刷多了还是恶心…
相关文章推荐
- 【.Net码农】App.Config详解及读写操作
- 测试数据库数据所在硬件写性能的脚本
- js 循环json
- Largest Rectangle in Histogram
- Dijkstra||Prim-POJ-1797-Heavy Transportation
- PDO的安全处理与事物处理
- 14年到15年失败堕落的一年
- Java总结篇系列:Java多线程(一)
- iOS地图系统导航
- wait notify notifyall
- 在手机上执行Enumeration intfs=NetworkInterface.getNetworkInterfaces();抛出socketexception
- Android+Eclipse+Maven环境搭建
- 【.Net码农】using的几种用法
- 信息二战炸弹:中国到美国咨询公司Say no
- android键盘弹出头部上移处理
- hdu1047(模拟大量的循环添加)
- html基础-属性
- LintCode 将整数A转换为B
- 黑马程序员---OC学习笔记之简单的单例模式实现
- Mac上安装 Ruby运行环境以及CocoaPods的安装使用教程