ZOJ3213-Beautiful Meadow
题意
有一个 \(n\times m\) 的方格纸,每个格子要么不能走,要么有一个权值。求一条简单路径权值和最大。简单路径是指不相交,不经过同一个格子的一条路经。\(n,m\le 8\) 。
分析
既然是路径,就要用到独立插头。这题的问题在于 起点终点不确定 。
不确定起点终点,关系到两种情况的处理。第一种是当前转移格子没有左插头和上插头。
格子可以不走,所以可以直接转移到 \(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;
}