“蔚来杯“2022牛客暑期多校训练营5 Don‘t Starve

题面:https://ac.nowcoder.com/acm/contest/33190/A

分析 : 因为是求最优化问题,应会想到DP和贪心
然而贪心并不可取,不可以只先走较长的边(的二长的边距离其 他点很远)

我们可以设 d p i , j dp_{i,j} dpi,j为从 i i i开始距离为 j j j时能得到的最多食物
可是在题目中 ( 0 < N < 2001 ) (0<N<2001) (0<N<2001) 而时间复杂度为 O ( n 3 ) O(n^3) O(n3),空间复杂度为 O ( n 4 ) O(n^4) O(n4),显然不可取
实际上,我们可以设 d p i dp_i dpi i i i时能得到的最多食物
so,状态转移方程便为 d p i = m a x ( d p i , d p 所有合法的起点 j + 1 ) dp_i=max(dp_i,dp_{所有合法的起点j}+1) dpi=max(dpi,dp所有合法的起点j+1)
现在,时间复杂度便只为 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( n 2 ) O(n^2) O(n2),可以通过这道题了
(对于转移时的存储,见代码)
代码:

#include<bits/stdc++.h>
#define LL long long

using namespace std;

const int MXN=2007;

struct Edge{
	int x,y;
	LL w;
};

Edge p[MXN*MXN];
int x[MXN],y[MXN];
int dp[MXN];

inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-'){
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*f;
}



bool cmp(Edge xx,Edge yy){
	return xx.w>yy.w;
}

int tp[MXN*MXN],top,V[MXN*MXN];

int main(){
	int i,j,k,n,len,res;
	LL v;
	memset(dp,200,sizeof(dp));
	n=read();
	for(i=1;i<=n;i++){
		x[i]=read(); y[i]=read();
	}
	dp[0]=0;
	len=0; res=0; top=0;
	for(i=0;i<=n;i++){
		for(j=i+1;j<=n;j++){
			v=1ll*(x[i]-x[j])*(x[i]-x[j])+1ll*(y[i]-y[j])*(y[i]-y[j]);
			len++;
			p[len].w=v;
			p[len].x=i; p[len].y=j;
			len++;
			p[len].w=v;
			p[len].x=j; p[len].y=i;
		}
	}
	sort(p+1,p+1+len,cmp);
	for(i=1;i<=len;i=j+1){
		j=i;
		while((j<len)&&(p[j+1].w==p[j].w)){
			++j;
		}
		top=0;
		for(;i<=j;i++){
			if(p[i].y){
				tp[++top]=p[i].y;
				V[top]=dp[p[i].x];
			}
		}	
		while(top){
			dp[tp[top]]=max(dp[tp[top]],V[top]+1);
			--top;
		}
	}
	for(i=0;i<=n;i++){
		res=max(res,dp[i]);
	}
	cout<<res<<"\n";
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值