[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

HDU 6447 YJJ’s Salesman (树状数组 + DP + 离散)

hdu6447

2018中国大学生程序设计竞赛 - 网络选拔赛 1010 YJJ's Salesman 离散化+树状数组维护区间最大值