• hdu 6447 YJJ's Salesman(离散化+树状数组优化dp)


    题意

    有一天,你想从城市A走到城市B,假设城市A在正方形$(0,0)$点,而城市B在正方形$(10^9,10^9)$点,你是能向东,向南或者向东南走,也就是说,假设你站在$(x,y)$点,你只能向$(x+1,y),(x,y+1)和(x+1,y+1)$这三个方向走。在这个矩阵的地图上,还散落着一些小村庄,村庄k坐落的位置为$(x_k,y,_k)$,如果你能从$(x_k-1,x_y-1)$的位置走到村庄k,那么你就可以得到$v_k$的金钱,问你可以得到的最大的金钱数量为多少?

    输入

    $T$组输入数据,范围$(1≤N≤10)$ 

    $N$个村庄,范围$(1≤N≤10^5) $

    接下来有$N$行,每行有三个数为$x_k,y_k,v_k(1≤v_k≤10^3)$

    输出

    可以得到的最大的金钱数

    思路

     首先我们可以明显的看到这是一个dp,状态转移方程为$dp[i][j]=max(dp[i-1][j-1]+v[i][j],dp[i-1][j],dp[i][j-1])$其中$dp[i][j]$表示的是在$(i,j)$位置得到的最大金钱数量。但是同时也会发现,这个地图有$(10^9,10^9)$那么大,直接用上面的状态转移方程根本不可能啊!转念一想,我们可以利用滚动数组,将二维的变为一维的,此时的状态转移方程为$dp[j]=max(dp[k])+v[i][j](1≤k≤j-1)$,其中$dp[j]$表示在第$j$列时得到的最大金钱数量,但是此时还是$10^9$的数组。

    再定睛一看,虽然地图很大,但是村庄很少,十分稀疏,最多只有$10^5$个,所以将横坐标离散化,这样数据范围就大大的降低。

    对于找$j-1$个$dp$的最大,可以利用树状数组维护前缀最大值,我们知道树状数组$tree[x]$放置的是从$x$开始的前$lowbit(x)$个数的和,那么我们可以将$tree[x]$变为从$x$开始的前$lowbit(x)$个数的最大值是多少,这时查找最大值的时间复杂度为$log^n$,整体算法的时间复杂度为$nlog^n$

    代码

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N = 1e5+10;
    const int inf = 0x3f3f3f3f;
    int T;
    int n;
    int num = 0;
    int tree[N];
    
    struct node
    {
        int x,y;
        int v;
    }data[N];
    
    bool cmp(node a,node b)
    {
        if(a.x<b.x) return true;
        else if(a.x==b.x)
        {
            if(a.y>b.y) return true;
            else return false;
        }
        else return false;
    }
    
    int lowbit(int x)
    {
        return x&-x;
    }
    
    void add(int x,int k)
    {
        while(x<=num)
        {
            tree[x] = max(tree[x],k);
            x = x + lowbit(x);
        }
    }
    
    int getmax(int x)
    {
        int maxx = -inf;
        while(x>=1)
        {
            maxx = max(maxx,tree[x]);
            x = x - lowbit(x);
        }
        return maxx;
    }
    
    
    int main()
    {
        cin>>T;
        while(T--)
        {
            cin>>n;
            memset(tree,0,sizeof(tree));
            vector <int> v;
            for(int i=0;i<n;i++)
            {
                scanf("%d%d%d",&data[i].x,&data[i].y,&data[i].v);
                v.push_back(data[i].y);
            }
            sort(v.begin(),v.end());
            v.erase(unique(v.begin(),v.end()),v.end());
            sort(data,data+n,cmp);
            int ans = -inf;
            num = v.size();
            for(int i=0;i<n;i++)
            {
                int j = upper_bound(v.begin(),v.end(),data[i].y)-v.begin();
                int w = data[i].v;
                tree[j] = ( j!=1 ? max(getmax(j-1)+w,tree[j]) : max(tree[j],w));
                add(j,tree[j]);
                ans = max(ans,tree[j]);
            }
            cout<<ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    Design:目录
    前端框架:template
    Template-ArtTemplate:artTemplate.js
    开发框架:AdminLTE
    开发框架:目录
    杂项:短网址
    httpd
    Java实现洛谷 P1428 小鱼比可爱
    Java实现洛谷 P1428 小鱼比可爱
    java实现洛谷P1308统计单词数
  • 原文地址:https://www.cnblogs.com/simplekinght/p/11335363.html
Copyright © 2020-2023  润新知