记录编号 88638 评测结果 AAAAAAAAAA
题目名称 [UVa 1094] 修筑水道 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 1.361 s
提交时间 2014-02-22 21:08:02 内存使用 18.45 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<vector>
using namespace std;
//本题下标从0开始
typedef long long ll;
const int SIZEN=20,SIZEM=9,HASHVAL=13131;
int N,M;//行数和列数
int opt[SIZEN][SIZEM][HASHVAL]={0};
int pre[SIZEN][SIZEM][HASHVAL]={0};
char board[SIZEN][SIZEM]={0};
class HASHMAP{
public:
	int hash[HASHVAL];
	vector<pair<ll,int> > st;
	void clear(void){
		memset(hash,-1,sizeof(hash));
		st.clear();
	}
	void insert(int x,int y,int op,int last,ll s,int f){
		if(st.size()>=HASHVAL){cout<<"hash overflow!"<<endl;}
		int hashpos=s%HASHVAL;
		while(hash[hashpos]!=-1){
			if(st[hash[hashpos]].first==s){
				if(st[hash[hashpos]].second<f){
					st[hash[hashpos]].second=f;
					opt[x][y][hash[hashpos]]=op;
					pre[x][y][hash[hashpos]]=last;
				}
				return;
			}
			hashpos++;
			if(hashpos==HASHVAL) hashpos=0;
		}
		hash[hashpos]=st.size();
		opt[x][y][st.size()]=op;
		pre[x][y][st.size()]=last;
		st.push_back(make_pair(s,f));
	}
};
HASHMAP F[2];
class STATE{
public:
	int plug[SIZEM+1];//储存轮廓线上诸插头
	bool exist[SIZEM+1];//储存轮廓线及左上诸格是否挖通
	void clear(void){memset(plug,0,sizeof(plug));memset(exist,0,sizeof(exist));}
	ll mdl(void){//调制
		ll ans=0;
		for(int i=M;i>=0;i--) ans=(ans<<1)+exist[i];
		for(int i=M;i>=0;i--) ans=(ans<<2)+plug[i];
		return ans;
	}
	void demdl(ll s){//解调
		for(int i=0;i<=M;i++) plug[i]=s&3,s>>=2;
		for(int i=0;i<=M;i++) exist[i]=s&1,s>>=1;
	}
	void nextline(void){//从这一行的末尾变到下一行的开头
		for(int i=M-1;i>=0;i--) plug[i+1]=plug[i],exist[i+1]=exist[i];
		plug[0]=exist[0]=0;
	}
};
int rightmatch(STATE &s,int k){//与s的第k位匹配的右插头
	int dta=1,temp;
	while(k<=M){
		k++;
		temp=s.plug[k];
		if(temp==1) dta++;
		else if(temp==2) dta--;
		if(dta==0) return k;
	}
	cout<<"bracket match error!"<<endl;
	return -1;
}
int leftmatch(STATE &s,int k){
	int dta=-1,temp;
	while(k>=0){
		k--;
		temp=s.plug[k];
		if(temp==1) dta++;
		else if(temp==2) dta--;
		if(dta==0) return k;
	}
	cout<<"bracket match error!"<<endl;
	return -1;
}
void changeblock(STATE &s,int y,int exi,int d,int r){//列数为y,exi为存在与否,d是下,r是右
	if(!exi){
		s.plug[y]=s.plug[y+1]=0;
		s.exist[y]=0;
	}
	else{
		s.plug[y]=d,s.plug[y+1]=r;
		s.exist[y]=1;
	}
}
void changematch(STATE &s,int y,int t){//把和插头y匹配的插头改成t
	if(s.plug[y]==1){
		s.plug[rightmatch(s,y)]=t;
	}
	else s.plug[leftmatch(s,y)]=t;
}
bool plug_exi(int x,int y,int dir){//2下4右
	if(dir==2&&x==N-1){
		if(y==M-1) return true;//右下角认为是向下挖了
		return false;
	}
	if(dir==4&&y==M-1) return false;
	return true;
}
void update(int k,int x,int y){//用F[k]去更新F[k^1],新增的一格是(x,y)
	F[k^1].clear();
	STATE S,T;
	int nowf,l,lu,u,ru,p,q;
	for(int i=0;i<F[k].st.size();i++){
		S.clear();
		S.demdl(F[k].st[i].first);
		if(y==0) S.nextline();
		nowf=F[k].st[i].second;
		//左:y-1,左上:y,上:y+1,右上:y+2
		l=y>0?S.exist[y-1]:0;
		lu=S.exist[y];
		u=S.exist[y+1];
		ru=y<M-1?S.exist[y+2]:0;
		p=S.plug[y],q=S.plug[y+1];//左插头和上插头
		if(p==0&&q==0){//什么都不放
			T=S;
			changeblock(T,y,0,0,0);
			F[k^1].insert(x,y,0,i,T.mdl(),nowf);
		}
		if(board[x][y]=='.'){//这里讨论放的
			if(p==0&&q==0){//新建连通分量
				if(!lu&&!u&&!l&&plug_exi(x,y,2)&&plug_exi(x,y,4)){
					T=S;
					changeblock(T,y,1,1,2);
					F[k^1].insert(x,y,1,i,T.mdl(),nowf+1);
				}
			}
			else if(p==0&&q>0){//上插头的延伸
				if(!l&&plug_exi(x,y,2)){
					T=S;
					changeblock(T,y,1,q,0);
					F[k^1].insert(x,y,1,i,T.mdl(),nowf+1);
				}
				if(!ru&&!l&&plug_exi(x,y,4)){
					T=S;
					changeblock(T,y,1,0,q);
					F[k^1].insert(x,y,1,i,T.mdl(),nowf+1);
				}
			}
			else if(p>0&&q==0){//左插头的延伸
				if(!u&&!ru&&plug_exi(x,y,2)){
					T=S;
					changeblock(T,y,1,p,0);
					F[k^1].insert(x,y,1,i,T.mdl(),nowf+1);
				}
				if(!u&&plug_exi(x,y,4)){
					T=S;
					changeblock(T,y,1,0,p);
					F[k^1].insert(x,y,1,i,T.mdl(),nowf+1);
				}
			}
			else if(p==1&&q==1){
				if(!lu){
					T=S;
					changematch(T,y+1,1);//将上插头对应的2改成1
					changeblock(T,y,1,0,0);
					F[k^1].insert(x,y,1,i,T.mdl(),nowf+1);
				}
			}
			else if(p==2&&q==2){
				if(!lu){
					T=S;
					changematch(T,y,2);//将左插头对应的1改成2
					changeblock(T,y,1,0,0);
					F[k^1].insert(x,y,1,i,T.mdl(),nowf+1);
				}
			}
			else if(p==2&&q==1){
				if(!lu){
					T=S;
					changeblock(T,y,1,0,0);
					F[k^1].insert(x,y,1,i,T.mdl(),nowf+1);
				}
			}
			if(p==2&&q==3){
				if(!lu){
					T=S;
					changematch(T,y,3);//将左插头对应的1改成3
					changeblock(T,y,1,0,0);
					F[k^1].insert(x,y,1,i,T.mdl(),nowf+1);
				}
			}
			if(p==3&&q==1){
				if(!lu){
					T=S;
					changematch(T,y+1,3);//将上插头对应的2改成3
					changeblock(T,y,1,0,0);
					F[k^1].insert(x,y,1,i,T.mdl(),nowf+1);
				}
			}
		}
	}
}
bool legal_end(ll s){//状态s是否是合法的终点
	//若合法,则只有一个独立插头,即M-1号
	ll plug=s&((1<<(2*(M+1)))-1);
	return plug==(3<<(2*(M-1)));
}
void work(void){
	int k=0;
	STATE start;
	F[k].clear();
	start.clear();
	start.exist[0]=1;//第一个格子
	start.plug[0]=3;//第一个格子向下伸出独立插头
	F[k].insert(0,0,1,-1,start.mdl(),1);
	start.plug[0]=0,start.plug[1]=3;//第一个格子向右伸出独立插头
	F[k].insert(0,0,1,-1,start.mdl(),1);
	for(int i=0;i<N;i++){
		for(int j=0;j<M;j++){
			if(!i&&!j) continue;
			update(k,i,j);
			k^=1;
		}
	}
	int ans=0,ansid=0;
	for(int i=0;i<F[k].st.size();i++){
		if(legal_end(F[k].st[i].first)&&F[k].st[i].second>ans){
			ans=F[k].st[i].second;
			ansid=i;
		}
	}
	char ansgrid[SIZEN][SIZEM]={0};
	memcpy(ansgrid,board,sizeof(board));
	int step;
	for(int i=N-1;i>=0;i--){
		for(int j=M-1;j>=0;j--){
			step=opt[i][j][ansid];
			if(step) ansgrid[i][j]='C';
			ansid=pre[i][j][ansid];
		}
	}
	cout<<ans<<endl;
	/*for(int i=0;i<N;i++){
		for(int j=0;j<M;j++) cout<<ansgrid[i][j];
		cout<<endl;
	}
	cout<<endl;*/
}
int kase=0;
bool read(void){
	memset(board,0,sizeof(board));
	memset(opt,0,sizeof(opt));
	memset(pre,0,sizeof(pre));
	scanf("%d%d",&N,&M);
	if(!N&&!M) return false;
	printf("Case %d:\n",++kase);
	string str;
	for(int i=0;i<N;i++){
		cin>>str;
		for(int j=0;j<M;j++) board[i][j]=str[j];
	}
	return true;
}
int main(){
	freopen("channel.in","r",stdin);
	freopen("channel.out","w",stdout);
	while(read()) work();
	return 0;
}