ZOJ3213-Beautiful Meadow

题意

有一个 \(n\times m\) 的方格纸,每个格子要么不能走,要么有一个权值。求一条简单路径权值和最大。简单路径是指不相交,不经过同一个格子的一条路经。\(n,m\le 8\)

分析

既然是路径,就要用到独立插头。这题的问题在于 起点终点不确定

不确定起点终点,关系到两种情况的处理。第一种是当前转移格子没有左插头和上插头。

plug

格子可以不走,所以可以直接转移到 \(a=b=0\) 。也可以新建连通块,\(a=1,b=2\)

若当前其他位置上的独立插头个数小于 2 ,那也可以在这里新建一个独立插头,\(a=3,b=0\)\(a=0,b=3\)

对于 \(x,y\) 中只有一个插头的情况,首先可以正常延伸。有了独立插头,我们还需要考虑 每个插头是否能够变成独立插头 。当左上为单插头,并且当前独立插头个数小于 2 ,那我们可以让这个插头变成独立插头。

\(x=0,y=3\)\(x=3,y=0\) ,这就意味着可能这条路径在这里终止。若除了这个插头就没有其他的插头,那可以在这里更新答案,不转移。\(x=y=3\) 同理。

复杂度为 \(O(nm|s|)\)

代码

把情况全部拿出来分开讨论,之后再看能不能合并在一起实现,这样不容易出错。

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define MapType cc_hash_table
using namespace std;
using namespace __gnu_pbds;
inline int read() {
    int x=0,f=1;
    char c=getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
typedef MapType<int,int> Map;
typedef MapType<int,int*> Mat;
typedef Map::iterator itt;
const int maxn=10;
int n,m,a[maxn][maxn],fx,fy;
Map f,g;
Mat mat;
template<typename T> inline void Max(T &x,T y) {x=max(x,y);}
inline int get(int x,int p) {return (x>>(p<<1))&3;}
inline int mod(int x,int p,int d) {return (x&(~(3<<(p<<1))))+(d<<(p<<1));}
inline void match(int x,int *&mt) {
    mt=new int[maxn];
    static int sta[maxn],top;
    top=0;
    for (int i=1;i<=m+1;++i) {
        const int d=get(x,i);
        if (d==1) sta[++top]=i; else if (d==2) {
            int y=sta[top--];
            mt[y]=i,mt[i]=y;
        }
    }
}
inline int& F(int x) {
    if (mat.find(x)==mat.end()) match(x,mat[x]);
    return f[x];
}
void dec(int x) {
    for (int j=0;j<=m+1;++j) printf("%d %c",((x>>(j<<1))&3)," \n"[j==m+1]);
    for (int j=0;j<=m+1;++j) printf("%d %c",j," \n"[j==m+1]);
}
void work() {
    f.clear(),g.clear();
    for (Mat::iterator it=mat.begin();it!=mat.end();++it) {
        delete [] it->second;
        it->second=NULL;
    }
    mat.clear();
    n=read(),m=read();
    int ans=0;
    for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) Max(ans,a[i][j]=read());
    for (int i=n;i;--i) for (int j=m;j;--j) if (a[i][j]) {
        fx=i,fy=j;
        goto zwl;
    }
    zwl:F(0)=0;
    for (int i=1;i<=n;++i) {
        f.swap(g),f.clear();
        for (itt it=g.begin();it!=g.end();++it) {
            const int &d=it->first,&w=it->second,s=get(d,0);
            if (get(d,m+1)==0) F(((d^s)<<2)|s)=w;
        }
        for (int j=1;j<=m;++j) {
            f.swap(g),f.clear();
            for (itt it=g.begin();it!=g.end();++it) {
                const int &d=it->first,&w=it->second,s=get(d,0),e=mod(mod(d,j,0),j+1,0);
                const int x=get(d,j),y=get(d,j+1),&aij=a[i][j],*mt=mat[d];
                if (!aij) {
                    if (x==0 && y==0) Max(F(d),w);
                    continue;
                } 
                if (x==0 && y==0) {
                    Max(F(d),w);
                    Max(F(mod(mod(d,j,1),j+1,2)),w+aij);
                    if (s>=2) continue;
                    int v=mod(d,0,s+1);
                    Max(F(mod(mod(v,j,3),j+1,0)),w+aij);
                    Max(F(mod(mod(v,j,0),j+1,3)),w+aij);
                } else if (x==0 || y==0) {
                    Max(F(mod(e,j,x+y)),w+aij);
                    Max(F(mod(e,j+1,x+y)),w+aij);
                    if (x+y==3) {
                        if (e<4) Max(ans,w+aij);
                    } else Max(F(mod(e,mt[j+(x==0)],3)),w+aij);
                } else if (x==1 && y==1) Max(F(mod(e,mt[j+1],1)),w+aij); 
                else if (x==1 && y==3) Max(F(mod(e,mt[j],3)),w+aij); 
                else if (x==2 && y==1) Max(F(e),w+aij); 
                else if (x==2 && y>1) Max(F(mod(e,mt[j],y)),w+aij); 
                else if (x==3 && (y==1 || y==2)) Max(F(mod(e,mt[j+1],3)),w+aij); 
                else if (x==3 && y==3 && e<4) Max(ans,w+aij); 
            }
        }
    }
    Max(ans,f[0]);
    printf("%d\n",ans);
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
#endif
    int T=read();
    while (T--) work();
    return 0;
}

转载于:https://www.cnblogs.com/owenyu/p/7518855.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值