hdu6447(树状数组+离散化优化dp)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yu121380/article/details/82460525

YJJ's Salesman

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2161    Accepted Submission(s): 809

Problem Description

YJJ is a salesman who has traveled through western country. YJJ is always on journey. Either is he at the destination, or on the way to destination.
One day, he is going to travel from city A to southeastern city B. Let us assume that A is (0,0) on the rectangle map and B (109,109). YJJ is so busy so he never turn back or go twice the same way, he will only move to east, south or southeast, which means, if YJJ is at (x,y) now (0≤x≤109,0≤y≤109), he will only forward to (x+1,y), (x,y+1) or (x+1,y+1).
On the rectangle map from (0,0) to (109,109), there are several villages scattering on the map. Villagers will do business deals with salesmen from northwestern, but not northern or western. In mathematical language, this means when there is a village k on (xk,yk) (1≤xk≤109,1≤yk≤109), only the one who was from (xk−1,yk−1) to (xk,yk) will be able to earn vk dollars.(YJJ may get different number of dollars from different village.)
YJJ has no time to plan the path, can you help him to find maximum of dollars YJJ can get.

Input

The first line of the input contains an integer T (1≤T≤10),which is the number of test cases.

In each case, the first line of the input contains an integer N (1≤N≤105).The following N lines, the k-th line contains 3 integers, xk,yk,vk (0≤vk≤103), which indicate that there is a village on (xk,yk) and he can get vk dollars in that village.
The positions of each village is distinct.

Output

The maximum of dollars YJJ can get.

Sample Input

1

3

1 1 1

1 2 2

3 3 1

Sample Output

3

Source

2018中国大学生程序设计竞赛 - 网络选拔赛

解析:首先,我们可以想到dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]+val[i][j]); 因为给出的图很大,(0,0)~(1e9,1e9)所以我们要对x轴离散化优化。x按照从大到小,y从小到大。然后从下往上,从左往右更新每一个点的val。维护dp[i],则dp[j]=max(dp[j],dp[i]+val[i][j])0<i<j-1,dp[i]表示在离散化后的0到j-i行中,最大价值的那个值。然后可以转换为树状数组区间找最值问题。

粗略的dp[j]=max(dp[j],getsum(0~i)+val)

但是为什么要这么排序呢?x按照从大到小,y从小到大。因为我们是从(0,0)点开始走的,每一列的其中一个位置,都要从它的上一列和上一行取得最大值。

(1,1)(1,2)(1,3)

(2,1)(2,2)(2,3)

(3,1)(3,2)(3,3)

就像我要取(3,3)的max值,我们要从(除了(3,3)点)中找一个最大值。又因为我们是从第一列开始,所以我们就要每次从x最大那一行开始更新,比如排序后先更新(3,1)然后我们要是最后是到(3,2)。我们还要更新(2,1),然后最后到(3,2)我们就要取1~3行的最值不包括第3列的行,因为我们还没到3列。具体看代码了解,有点说不清楚

#include<bits/stdc++.h>
using namespace std;

#define e exp(1)
#define pi acos(-1)
#define mod 1000000007
#define inf 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
#define mem(a,b) memset(a,b,sizeof(a))
int gcd(int a,int b){return b?gcd(b,a%b):a;}

const int maxn=1e5+10;
int n,c[maxn],x[maxn];
struct node{
	int x,y,w;
	bool operator < (const node &r)const{
		if(y==r.y)return x>r.x;
		return y<r.y;
	}
}a[maxn];
int lowbit(int x)
{
	return x&(-x);
}
void add(int i,int val)
{
	while(i<=n)
	{
		c[i]=max(c[i],val);
		i+=lowbit(i);
	}
}
int getsum(int i)
{
	int ans=0;
	while(i>0)
	{
		ans=max(ans,c[i]);
		i-=lowbit(i);
	}
	return ans;
}

int main()
{
	int T;scanf("%d",&T);
	while(T--)
	{
		mem(c,0);
		scanf("%d",&n);
		for(int i=1; i<=n; i++)
		{
			scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
			x[i]=a[i].x;
		}
		sort(x+1,x+n+1);
		sort(a+1,a+n+1);
		int ans=0;
		for(int i=1; i<=n; i++)
		{
			int cnt=lower_bound(x+1,x+n+1,a[i].x)-x;//离散化 
			int num=a[i].w+getsum(cnt-1);//更新0~cnt-1行 的最值 
			ans=max(ans,num);
			add(cnt,num);//在cnt行插入num。 
		}
		printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/yu121380/article/details/82460525