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

"蔚来杯"2022牛客暑期多校训练营5 A:Don’t Starve

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

题面

NIO purchased a new game, Don’t Starve, a sandbox game published by Klei Entertainment Inc. This game revolves around a scientist named Wilson who finds himself in a dark and gloomy world and must survive for as long as possible.

In the very beginning, NIO should help Wilson to gather some food for survival. Assume that when controlling Wilson to walk towards a location on the map, NIO should keep pressing the left button on the mouse, and when Wilson comes to the place where there is food, NIO should stop pressing the mouse, but press the space key on the keyboard to collect the food at this location. As NIO will feel tired of pressing the mouse for a long time and his finger will become very uncomfortable after a long time of pressing, the time he is willing to press the mouse after each collection is strictly decreased. Suppose there are NN locations on the 2-D plane, and at each point, there is only one unit of food. And NIO will start at the original point on the plane. You can assume that each point has an infinite number of food items, but only one can be taken at a time.

What is the maximum amount of food can NIO get for Wilson? Note that the food will be refreshed after Wilson left.

大意

给定平面上 n n n 个点,从原点出发直线前往这些点收集食物,收集完再前往下一个点。每当离开一个有食物的点后该点食物刷新,每次移动距离严格下降。问最多收集到多少食物。 n ≤ 2 × 1 0 3 n≤2×10^3 n2×103

题解

可以看出选择dp,但如果是普通dp则会超时和超内存(时间为 O ( n 4 ) \Omicron(n^4) O(n4),空间为 O ( n 3 ) \Omicron(n^3) O(n3)),因此需要优化处理。注意如果每次都选符合条件的最长边,可能不是最优解,存在反例。

  • f [ i ] [ j ] f[i][j] f[i][j] 表示从i走到j后还能走拿多少食物,因为这个状态与之前的状态无关,得到转移方程 f [ i ] [ j ] = m a x ( f [ j ] [ k ] ) f[i][j]=max(f[j][k]) f[i][j]=max(f[j][k]) 其中, j − > k j−>k j>k 这条路的长度小于 i − > j i−>j i>j 的长度,因此可以先将所有边按长度从小到大排序,这样在考虑当前的路时,之前的路都是可以走的。可以用 s [ i ] s[i] s[i] 表示目前从 i i i 出发最远可以走多远,注意如果有长度相同通往同一个点的路,应该同时被考虑到。
  • 当然也可以用反向 d p dp dp,设 d p i dp_i dpi 是从点 i i i 出发所能得到的最大食品数,从小到大转移,如上,这样操作使得在考虑当前的路时,之前的路都是可以走的
    转移方程:
    d p i = m a x ( 1 + d p j ) dp_i=max(1+dp_j) dpi=max(1+dpj)

参考代码

是第一种做法

#include <bits/stdc++.h>
using namespace std;
const int maxn=5000006;
const int maxm=2003;
struct edge{
    int u,v,w;
}ed[maxn];
int n,cnt;
int x[maxn],y[maxn],s[maxm];
int f[maxm][maxm];
bool cmp(edge x,edge y)
{
    return x.w<y.w;
}
int main()
{
    bool flag=false;
    cin>>n;
    for(int i=1;i<=n;++i){
        cin>>x[i]>>y[i];
        if(!x[i]&&!y[i]) flag=true;
        for(int j=0;j<i;++j) 
        ed[++cnt]=edge{i,j,(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])};
    }
    sort(ed+1,ed+cnt+1,cmp);
    for(int i=1;i<=cnt;++i) {
        int j=i;
        while(ed[i].w==ed[j+1].w&&j<cnt) ++j;
        for(int k=i;k<=j;++k) {
            int u=ed[k].u,v=ed[k].v;
            if(v) f[u][v]+=s[v]+1;
            if(u) f[v][u]+=s[u]+1;
        }
        for(int k=i;k<=j;++k) {
            int u=ed[k].u,v=ed[k].v;
            if(u) s[u]=max(s[u],f[u][v]);
            if(v) s[v]=max(s[v],f[v][u]);
        }
        i=j;
    }
    int ans=0;
    for(int i=1;i<=n;++i) ans=max(ans,f[0][i]);
    cout<<ans+flag<<endl;
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值