1. 程式人生 > >HDU 6447 YJJ’s Salesman (樹狀數組 + DP + 離散)

HDU 6447 YJJ’s Salesman (樹狀數組 + DP + 離散)

isp code XML .org ide oid data- element scanf

題意:

二維平面上N個點,從(0,0)出發到(1e9,1e9),每次只能往右,上,右上三個方向移動,
該N個點只有從它的左下方格點可達,此時可獲得收益。求該過程最大收益。

分析:我們很容易就可以想到用DP,假設這個位置是相對上一個位置的方向而來,但是復雜度達到N^2 ,這樣是不行的;

我們可以利用坐標的信息,將所有的點離散化後,以x優先按小到大排序,按y按大到小排序,這時維護一個DP(i) ,表示第I列的最值。

j=0i?1j=0→i?1
dp[i]max(dp[i[,dp[j]+val)dp[i]←max(dp[i[,dp[j]+val)

因為x已經按從小到大排好序了,y也是從大到小更新的,故保證了可達性。

對於每次更新,可以用線段樹或者樹狀數組維護最大值,此時算法復雜度O(NlogN)

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
int n,hashx[100001],hashy[100001],dp[100001],tree[100001];
struct no
{
    int x,y,w;
}a[100001];
bool cmp(no a, no b)
{
    if(a.x==b.x)
    return a.y>b.y;
    return a.x<b.x;
    
}
//離散化 void init( ) { for(int i=1 ; i<=n ; i++) { hashx[i] = a[i].x; hashy[i] = a[i].y; } sort(hashx+1,hashx+1+n); sort(hashy+1,hashy+1+n); int cntx = unique(hashx+1,hashx+1+n)-hashx; int cnty = unique(hashy+1,hashy+1+n)-hashy; for(int i=1 ; i<=n ; i++) { a[i].x
= lower_bound(hashx+1,hashx+1+cntx,a[i].x)-hashx; a[i].y = lower_bound(hashy+1,hashy+1+cnty,a[i].y)-hashy; } } int lowbit(int x) { return x&(-x); } void update(int pos) { while(pos <= n) { tree[pos] = dp[pos]; for(int i=1;i<lowbit(pos);i<<=1) tree[pos] = max(tree[pos],tree[pos-i]); pos += lowbit(pos); } } int query(int l, int r) { int ans = 0; while(r>=l) { ans = max(ans,dp[r]); if(l==r) break; for(--r;r-l>=lowbit(r);r-=lowbit(r)) ans = max(ans,tree[r]); } return ans; } int main( ) { int t; scanf("%d",&t); while (t--) { scanf("%d",&n); for(int i=1 ; i<=n ; i++) { scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w); } sort(a+1,a+1+n,cmp); init( ); memset(dp,0,sizeof(dp)); memset(tree,0,sizeof(tree)); for(int i=1 ; i<=n ; i++) { dp[a[i].y]=max(dp[a[i].y],query(1,a[i].y-1)+a[i].w); update(a[i].y); } int ans = 0; for(int i=1;i<=n;++i) ans = max(ans,dp[i]); printf("%d\n",ans); } return 0; }
View Code

HDU 6447 YJJ’s Salesman (樹狀數組 + DP + 離散)