P1117 [NOI2016] 优秀的拆分

#include<bits/stdc++.h>
using namespace std;
 
struct DP{
	int zan[6000000],gs[6000000];
	int top;
}dp[2];
 
int n,m,a,b;
int dt[15][15];
int HASH[8000000];//不会用哈希 QaQ 
 
int ans_MAX,ans_MIN;
int fx[5]={0,0,0,1,-1};
int fy[5]={0,1,-1,0,0};
 
bool check(int x){//检查 x 是否在范围内 
	if(x<1||x>n)return 0;
	return 1;
}
int maxx(int x,int y){//MAX 
	return x>y? x:y;
}
 
void read(){//读入 
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			dt[i][j]=1;
		}
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d",&a,&b);
		dt[n-a+1][b]=0;
	}
	ans_MAX=0;
	ans_MIN=0;
} 
void bfs(){//普通的 BFS 
	ans_MIN=0;
	int dl[250][2],l=1,r=1;
	dl[r][0]=1,dl[r][1]=1;
	int pd[15][15];
	memset(pd,0,sizeof(pd));
	pd[1][1]=1;
	while(l<=r){
		int jr=r;
		for(int i=l;i<=jr;i++){
			int x=dl[i][0],y=dl[i][1];
			for(int j=1;j<=4;j++){
				int xx=x+fx[j],yy=y+fy[j];
				if(dt[xx][yy]&&!pd[xx][yy]&&check(xx)&&check(yy))r++,dl[r][0]=xx,dl[r][1]=yy,pd[xx][yy]=1;
			}
		}
		l=jr+1;ans_MIN++;
		if(pd[n][n])return ;
	}
	ans_MIN=-1;
}
void csh(){//初始化 
	dp[1].top=0;
	dp[0].top=2;
	dp[0].zan[1]=(1<<(n<<1));
	dp[0].gs[1]=1;
	dp[0].zan[2]=(1<<((n-1)<<1));
	dp[0].gs[2]=1;
}
void add(int k,int gs,int y){//加入状态 
 
	if(y==n){//行末特判 
		if(k&3)return ;
		k>>=2;
	}
	int zz=HASH[k];
	if(!zz){
		dp[1].top++;
		zz=HASH[k]=dp[1].top;
		dp[1].zan[zz]=k;
		dp[1].gs[zz]=gs;
	}
	else{
		dp[1].gs[zz]=maxx(dp[1].gs[zz],gs);
	}
}
void gb(int &k,int pd,int st){//改变不合法括号 
	int jy[20],kk=k;
	int top=0;
	for(int i=n+1;i>0;i--){//解压 
		jy[i]=(kk&3);
		kk>>=2;
	}
	if(pd==1){//栈 
		for(int i=st+2;i<=n+1;i++){
			if(jy[i]==1)top++;
			else if(jy[i]==2){
				if(top)top--;
				else{
					k-=(1<<((n-i+1)<<1));
					return ;
				}
			}
		}
	}
	else{//栈 
		for(int i=st-1;i>0;i--){
			if(jy[i]==2)top++;
			else if(jy[i]==1){
				if(top)top--;
				else{
					k+=(1<<((n-i+1)<<1));
					return ;
				}
			}
		}
	}
}
void js(int x,int y){//计算 
 
	int left=3<<((n+1-y)<<1),up=left>>2;
	while(dp[0].top){
		int k=dp[0].zan[dp[0].top],gs=dp[0].gs[dp[0].top];dp[0].top--;//取出
		 
		int ztu=(k&up),ztl=(k&left);
		
		k=k-ztu-ztl;//将 下,右 插头 清零 
		
		ztl>>=((n+1-y)<<1);//将状态转化为 1,2 (方便检查) 
		ztu>>=((n-y)<<1);
		if(!(ztu|ztl)){//没有插头 
			add(k,gs,y);//不走 空着 
			if(dt[x][y])
				add(k|(up<<1),gs+1,y);//空地可以走 
		}
 
		else if(!dt[x][y])continue;//有插头并且是障碍不合法
 
		else if(ztu>0&&ztl>0){//有两个插头 
		
			if(ztu==ztl){//相同 
				int kk=k;
				gb(kk,ztu,y);//改变不合法插头 
				
				add(kk,gs+1,y);// 走 
			}
			else if(ztu==1){
				add(k,gs+1,y);// up 为 1 时合法 
			}
			else continue;   // up 为 2 时不合法 
		}
		else{
			int ad=(ztu|ztl);//只有一个插头 
			add(k|(ad<<((n-y)<<1)),gs+1,y);//两种出法 
			add(k|(ad<<((n+1-y)<<1)),gs+1,y);
		}
	}
	dp[0]=dp[1];
	while(dp[1].top)HASH[dp[1].zan[dp[1].top--]]=0;//清空 数组 
}
void CT(){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==1&&j==1)continue;//第一个点初始化过了 
			if(i==n&&j==n)return ;//最后一个点,也就是终点不用计算 
			js(i,j);
		}
	}
}
void dq(){//读取 读取答案 ans_MAX 
	for(int i=1;i<=dp[0].top;i++){
		if(dp[0].zan[i]==1||dp[0].zan[i]==4)ans_MAX=maxx(ans_MAX,dp[0].gs[i]);
	}
}
void ZY_DP(){//装压DP 
	csh(); // 初始化 
	CT(); //  插头DP CT 
	dq();//  读取 
}
int main(){
	read();//输入 
	
	bfs();//最短路 
	
	ZY_DP();//最长路 
	
	cout<<ans_MAX-ans_MIN<<endl;//时差 
}
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值