首页 > 代码库 > BZOJ 3111: [Zjoi2013]蚂蚁寻路

BZOJ 3111: [Zjoi2013]蚂蚁寻路

Sol

DP.

首先观察转折,画画图,看看移动路线,可以非常轻易的发现如果走到起点的下方是回不去的..

然后它就相当于一个底部是平的,顶部凹凹凸凸的形状,每右转两次或左转两次就会形成小矩阵,这样就可以来DP了.

首先一个非常简单的思路,就是f[k][i][j]表示取到第j列高度为h最大权值,枚举上一个转折点,复杂度 \(O(n^5k)\) 因为上一个点一定是与他同一行的,枚举行,枚举次数,枚举列,枚举高度,枚举上一个位置的列,枚举上一个位置的行.

我们可以优化,让他一次DP一行,其实可以发现就是取高度大于或小于当前高度,列小于当前的点最大值,这个最大值我们可以记录下来然后 \(O(1)\) 转移,再加上每列前缀和,就是 \(O(n^3k)\) 的了.

Code

/**************************************************************    Problem: 3111    User: BeiYu    Language: C++    Result: Accepted    Time:172 ms    Memory:1460 kb****************************************************************/ #include<cstdio>#include<cstring>#include<iostream>using namespace std; const int N = 105;const int K = 25;const int INF = 0x3fffffff; int n,m,k,ans;int a[N][N],d[N][N];int f[N][N],g[N][N]; inline int in(int x=0,char ch=getchar(),int v=1){    while(ch!=‘-‘&&(ch>‘9‘||ch<‘0‘)) ch=getchar();if(ch==‘-‘) v=-1,ch=getchar();    while(ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar();return x*v; }int main(){//  freopen("in.in","r",stdin);    n=in(),m=in(),k=in();ans=-INF;    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=in();//  for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) d[i][j]=d[i-1][j]+a[i][j];    for(int i=1;i<=n;i++){        memset(f,0x8f,sizeof(f)),memset(g,0x8f,sizeof(g)),memset(d,0,sizeof(d));        for(int u=1;u<=m;u++) for(int v=i;v;v--) d[v][u]=d[v+1][u]+a[v][u];        for(int u=1;u<=m;u++) for(int v=1;v<=i;v++) g[v][u]=max(g[v][u-1],0)+d[v][u];        for(int q=1;q<=k;q++){            for(int u=1;u<=m;u++) for(int v=1,tmp=-INF;v<=i;v++) tmp=max(tmp,g[v-1][u-1]),f[v][u]=max(f[v][u-1],tmp)+d[v][u];            for(int u=1;u<=m;u++) for(int v=i,tmp=-INF;v;v--) tmp=max(tmp,f[v+1][u-1]),g[v][u]=max(tmp,g[v][u-1])+d[v][u];        }        for(int u=1;u<=m;u++) for(int v=1;v<=i;v++) ans=max(ans,g[v][u]);    }cout<<ans<<endl;    return 0;}   

  

BZOJ 3111: [Zjoi2013]蚂蚁寻路