[HDU 6447][YJJ's Salesman][2018CCPC网络选拔赛 1010][离散化+线段树+DP]
Posted moonstviolet
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HDU 6447][YJJ's Salesman][2018CCPC网络选拔赛 1010][离散化+线段树+DP]相关的知识,希望对你有一定的参考价值。
链接:
http://acm.hdu.edu.cn/showproblem.php?pid=6447
题意:
左上角(0,0),右下角(10^9,10^9)的网格,其中有n(1<=n<=10^5)个方格内有权值。
一次只能沿右,下,右下三个方向走一个格子,只有沿右下方向走到格子里才可以获得权值。
问从(0,0)到(10^9,10^9)的路径最大权值是多少。
思路:
网格路径权值问题,第一感考虑DP,x从上往下,y从左往右刷表,状态转移方程为dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]+w[i][j]).
存在两个问题:
(1)坐标范围10^9,数组开不下
离散化把坐标映射到[1,n],比如一维数组{1,100,10,10},先排序{1,10,10,100},然后离散化成{1,2,2,3}。
(2)n的范围为1e5,O(n^2)的DP时空复杂度均爆表。
联想背包问题的滚动数组,实际上我们可以只开一维数组,此时y需要从右往左刷表,状态转移方程为dp[j]=max(dp[j],dp[k]+w[i][j]),
dp[k]是区间[1,j-1]最大值,区间最值查询显然可以用线段树以O(logn)的复杂度来处理,总体复杂度O(nlogn)。
比赛时我怎么做不出来呢?菜到自闭orz~
代码:
1 #include<bits/stdc++.h> 2 #define rep(i,a,b) for (int i=a;i<=b;i++) 3 using namespace std; 4 5 const int MAXN=(int)1e5+10; 6 7 struct Point{ 8 int x,y,w; 9 } p[MAXN]; 10 int posHash[MAXN]; 11 void initHash(int n); 12 13 struct Node{ 14 int l,r,val; 15 } tree[MAXN*4]; 16 void build(int id,int l,int r); 17 void update(int id,int pos,int w); 18 int query(int id,int L,int R); 19 20 int main() 21 { 22 int T; 23 cin>>T; 24 while (T--) { 25 int n; 26 scanf("%d",&n); 27 rep(i,0,n-1) { 28 scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].w); 29 } 30 31 initHash(n); 32 build(1,1,n); 33 34 int sum=0; 35 rep(i,0,n-1) { 36 int temp=p[i].w; 37 if (p[i].y!=1) { 38 temp+=query(1,1,p[i].y-1); 39 } 40 update(1,p[i].y,temp); 41 sum=max(sum,temp); 42 } 43 44 printf("%d ",sum); 45 } 46 return 0; 47 } 48 49 void initHash(int n) 50 { 51 sort(p,p+n,[](const Point &a,const Point &b) 52 {return a.x<b.x;}); 53 posHash[0]=1; 54 rep(i,1,n-1) { 55 if (p[i].x==p[i-1].x) { 56 posHash[i]=posHash[i-1]; 57 } else { 58 posHash[i]=posHash[i-1]+1; 59 } 60 } 61 rep(i,0,n-1) { 62 p[i].x=posHash[i]; 63 } 64 65 sort(p,p+n,[](const Point &a,const Point &b) 66 {return a.y<b.y;}); 67 posHash[0]=1; 68 rep(i,1,n-1) { 69 if (p[i].y==p[i-1].y) { 70 posHash[i]=posHash[i-1]; 71 } else { 72 posHash[i]=posHash[i-1]+1; 73 } 74 } 75 rep(i,0,n-1) { 76 p[i].y=posHash[i]; 77 } 78 79 sort(p,p+n,[](const Point &a,const Point &b) 80 {return a.x==b.x? a.y>b.y : a.x<b.x;}); 81 } 82 83 void build(int id,int l,int r) 84 { 85 tree[id].l=l,tree[id].r=r; 86 if (l==r) { 87 tree[id].val=0; 88 return; 89 } 90 int mid=(l+r)/2; 91 build(id*2,l,mid); 92 build(id*2+1,mid+1,r); 93 tree[id].val=max(tree[id*2].val,tree[id*2+1].val); 94 } 95 96 void update(int id,int pos,int w) 97 { 98 int l=tree[id].l,r=tree[id].r; 99 if (l==r && r==pos) { 100 tree[id].val=max(tree[id].val,w); 101 return; 102 } 103 int mid=(l+r)/2; 104 if (pos<=mid) { 105 update(id*2,pos,w); 106 } else { 107 update(id*2+1,pos,w); 108 } 109 tree[id].val=max(tree[id*2].val,tree[id*2+1].val); 110 } 111 112 int query(int id,int L,int R) 113 { 114 int l=tree[id].l,r=tree[id].r; 115 if (L<=l && r<=R) { 116 return tree[id].val; 117 } 118 int mid=(l+r)/2; 119 if (R<=mid) { 120 return query(id*2,L,R); 121 } else if (mid<L) { 122 return query(id*2+1,L,R); 123 } else { 124 return max(query(id*2,L,mid),query(id*2+1,mid+1,R)); 125 } 126 }
以上是关于[HDU 6447][YJJ's Salesman][2018CCPC网络选拔赛 1010][离散化+线段树+DP]的主要内容,如果未能解决你的问题,请参考以下文章
[HDU 6447][YJJ's Salesman][2018CCPC网络选拔赛 1010][离散化+线段树+DP]
HDU6447 YJJ's Salesman 2018中国大学生程序设计竞赛 - 网络选拔赛1010 离散化+线段树+DP
HDU6447 YJJ's Salesman-2018CCPC网络赛-线段树求区间最值+离散化+dp