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;
}
posted @ 2017-09-14 08:53  permui  阅读(214)  评论(0编辑  收藏  举报