zoukankan      html  css  js  c++  java
  • bzoj1897. tank 坦克游戏(决策单调性分治)

    题目描述

    有这样一款新的坦克游戏。在游戏中,你将操纵一辆坦克,在一个N×M的区域中完成一项任务。在此的区域中,将会有许多可攻击的目标,而你每摧毁这样的一个目标,就将获得与目标价值相等的分数。只有获得了最高的分数,任务才算完成。同时,为了增加游戏的真实性和难度,该游戏还做了以下的限制:

    1)坦克有射程r的限制。为方便计算,射程r规定为:若坦克位于(x, y)格,则它可攻击的目标(x1, y1)必须满足|x-x1|, |y-y1|∈[0, r]。

    2)对坦克完成任务的时间有严格限制,规定为t秒。其中,坦克每进行一次移动都需1秒的时间,每攻击一个目标也需1秒的时间。时间一到t秒,便对此次任务进行记分。

    3)坦克最初位于左上角,且移动方向只准是向右或向下,每次只允许移动一格。

    在以上的限制条件下,要完成该任务便成为了一件很难事情。因此,你必须为此编写一个程序,让它助你完成这个艰巨的任务。

    输入格式

    第一行四个整数N、M、r、t,分别表示区域的长、宽,以及射程和完成任务时间。

    接下来N行是一个N×M的矩阵,对应每个位置上目标的价值。

    输出格式

    输出文件仅一个数max,即该任务中可得到的最高分数。

    样例

    样例输入

    5 5 2 7
    0 5 0 0 4
    0 0 0 0 2
    0 0 0 0 0
    0 0 0 0 0
    5 0 3 0 11

    样例输出

    21

    数据范围与提示

    1≤N、M≤500,1≤r≤100,1≤t≤250。

    对于20%的数据有:1≤N、M≤10。

    对于60%的数据有:1≤N、M≤50,1≤r≤10。

    对于80%的数据有:1≤N、M≤100,1≤r≤20。


    设$f[i][j][k]$表示到$(i,j)$为止打$k$个的最大价值

    注意到每步打目标的个数一定是单调不降的

    证明....挂一神犇的blog

    每次转移时用决策单调性分治优化

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define re register
    using namespace std;
    int read(){
        char c=getchar(); int x=0;
        while(c<'0'||c>'9') c=getchar();
        while('0'<=c&&c<='9') x=x*10+c-48,c=getchar();
        return x;
    }
    #define N 505
    int cmp(int A,int B){return A>B;}
    int n,m,R,T,ans,k=1,a[N][N],f[2][N][253],h[N*N],tp,g[N],v[N];
    void solve(int l,int r,int dl,int dr){
        if(l>r||dl>dr) return ; 
        int mm=(l+r)/2,dm=dl;
        for(int i=dl;i<=min(mm,dr);++i)
            if(v[mm]<g[mm-i]+h[i])
                v[mm]=g[mm-i]+h[i],dm=i;
        solve(l,mm-1,dl,dm);
        solve(mm+1,r,dm,dr);
    }
    int main(){
        n=read(); m=read(); R=read(); T=read();
        for(re int i=1;i<=n;++i)
            for(re int j=1;j<=m;++j)
                a[i][j]=read();
        for(re int i=1;i<=R+1;++i)
            for(re int j=1;j<=R+1;++j)
                if(a[i][j]) h[++tp]=a[i][j];
        sort(h+1,h+tp+1,cmp); tp=min(tp,T);//注意最多取T个
        for(re int i=1;i<=tp;++i) f[1][1][i]=f[1][1][i-1]+h[i];
        int _n=max(1,n-R),_m=max(1,m-R);
        for(re int i=1;i<=_n;++i,k^=1)
            for(re int j=1;j<=_m;++j){
                int lim=T-i-j+2;
                if(lim<=0) continue;
                if(i>1){
                    for(re int u=0;u<=lim;++u) v[u]=g[u]=f[k^1][j][u];
                    tp=0;
                    for(re int u=max(1,j-R);u<=min(m,j+R);++u)
                        if(a[i+R][u]) h[++tp]=a[i+R][u];
                    sort(h+1,h+tp+1,cmp);
                    for(re int u=1;u<=tp;++u) h[u]+=h[u-1];
                    solve(1,lim,0,tp);
                    for(re int u=0;u<=lim;++u) f[k][j][u]=max(f[k][j][u],v[u]);
                }
                if(j>1){
                    for(re int u=0;u<=lim;++u) v[u]=g[u]=f[k][j-1][u];
                    tp=0;
                    for(re int u=max(1,i-R);u<=min(n,i+R);++u)
                        if(a[u][j+R]) h[++tp]=a[u][j+R];
                    sort(h+1,h+tp+1,cmp);
                    for(re int u=1;u<=tp;++u) h[u]+=h[u-1];
                    solve(1,lim,0,tp);
                    for(re int u=0;u<=lim;++u) f[k][j][u]=max(f[k][j][u],v[u]);
                }
                while(lim) ans=max(ans,f[k][j][lim--]);
            }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    <mySql完全手册>2011031401
    <海量数据库解决方案>2011030801
    检索
    <mySql完全手册>2011022401
    <自己动手写操作系统>2011031601
    数据结构和算法基础
    <海量数据库解决方案>2011031001
    <自己动手写操作系统>2011032101
    Delphi方法类型
    .NET下的Login机制
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/11359685.html
Copyright © 2011-2022 走看看