hdu1078(dp)

题目链接
题意:老鼠开始在(0,0)的位置,每次只能横向或纵向走不超过 k 步,且下一个位置的能量要比前一个位置的能量大,求老鼠最多得到的能量和
思路:最开始写了个 O( N 4 N^{4} N4) 的 dp,用 n * n 的 a 数组记录下标(x,y)和当前位置的值,dp[i] 表示的是走到 a[i] 最多的价值和

#include <cstring>
#include <iostream>
#include <algorithm>
#define mem(x,y) memset(x,y,sizeof x)
#define cl1(x,y,n) for(int c1_i=0;c1_i<n;c1_i++) x[c1_i]=y
#define cl2(x,y,n,m) for(int c2_i=0;c2_i<n;c2_i++) for(int c2_j=0;c2_j<m;c2_j++) x[c2_i][c2_j]=y
#define inf (~0U>>2)
using namespace std;
const int maxn=1e2+10;
const int maxm=1e3+10;
struct node{int x,y,v;}a[maxn*maxn];
int n,k,dp[maxn*maxn];
bool cmp(node b,node c)
{
    return b.v<c.v;
}
int _abs(int b)
{
    return b>=0?b:-b;
}
bool judge(node b,node c)
{
    return b.x==c.x?_abs(b.y-c.y)<=k:(b.y==c.y?_abs(b.x-c.x)<=k:false);
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    while(cin>>n>>k&&n!=-1)
    {
        for(int i=0;i<n*n;i++) cin>>a[i].v,a[i].x=i/n,a[i].y=i%n;
        n*=n;
        sort(a,a+n,cmp);
        cl1(dp,-inf,n);///初始化为一个极小值后就不用在 dp 过程中判断 dp[j] 是否走过,最开始没考虑到,初始化为 0,一直错
        int id;
        for(int i=0;i<n;i++) if(a[i].x==0&&a[i].y==0) {id=i;break;}///v 比(0,0)位置小的没必要再考虑
        dp[id]=a[id].v;
        int ans=dp[id];
        for(int i=id+1;i<n;i++)
        {
            for(int j=id;j<i;j++)
                if(judge(a[i],a[j])&&a[i].v>a[j].v)
                    dp[i]=max(dp[i],dp[j]+a[i].v);
            ans=max(ans,dp[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

由于老鼠只能横着走或竖着走,没必要判断每一个比 a[i].v 小的点,只需要判断 (x - k,y) ~(x + k,y) 和 (x,y - k)~(x,y + k)的点即可,复杂度 O N 2 N^{2} N2 * 4K)

#include <cstring>
#include <iostream>
#include <algorithm>
#define mem(x,y) memset(x,y,sizeof x)
#define cl1(x,y,n) for(int c1_i=0;c1_i<n;c1_i++) x[c1_i]=y
#define cl2(x,y,n,m) for(int c2_i=0;c2_i<n;c2_i++) for(int c2_j=0;c2_j<m;c2_j++) x[c2_i][c2_j]=y
#define inf (~0U>>2)
using namespace std;
const int maxn=1e2+10;
const int maxm=1e3+10;
struct node{int x,y,v;}a[maxn*maxn];
int n,k,b[maxn][maxn],dp[maxn][maxn];
bool cmp(node b,node c)
{
    return b.v<c.v;
}
int _abs(int b)
{
    return b>=0?b:-b;
}
bool judge(node b,node c)
{
    return b.x==c.x?_abs(b.y-c.y)<=k:(b.y==c.y?_abs(b.x-c.x)<=k:false);
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    while(cin>>n>>k&&n!=-1)
    {
        cl2(dp,-inf,n,n);
        for(int i=0;i<n*n;i++) cin>>a[i].v,a[i].x=i/n,a[i].y=i%n,b[i/n][i%n]=a[i].v;
        ///n*=n;
        sort(a,a+n*n,cmp);
        int id;
        for(int i=0;i<n*n;i++) if(a[i].x==0&&a[i].y==0) {id=i;break;}
        dp[0][0]=a[id].v;
        int ans=dp[0][0];
        for(int i=id+1;i<n*n;i++)
        {
            int xx=a[i].x,yy=a[i].y,vv=a[i].v;
            for(int j=max(0,xx-k);j<=min(n-1,xx+k);j++)
                if(j!=xx&&b[j][yy]<vv) dp[xx][yy]=max(dp[xx][yy],dp[j][yy]+vv);
            for(int j=max(0,yy-k);j<=min(n-1,yy+k);j++)
                if(j!=yy&&b[xx][j]<vv) dp[xx][yy]=max(dp[xx][yy],dp[xx][j]+vv);
            ans=max(ans,dp[xx][yy]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值