麦当劳叔叔的难题

题目描述

话说我们铭铭小朋友成功的回答了爸爸的问题,自然少不了要去索要些奖励,抠门的爸爸一看报纸,嘿,门口的麦当劳在搞活动,还有免费午餐哦,不过前提条件:得正确回答麦当劳叔叔的问题。

问题是这样描述的:

“我面前有很多个小朋友,我希望你帮我找到一个最聪明的小朋友。我心目中最聪明的就是第一个跑进麦当劳大门的,我希望你帮我找出最聪明和最不聪明的小朋友,可能的最大的到达时间差。但是,小朋友只能按照一个特殊的规则前进。小朋友面前有一个 𝑛×𝑛n×n 的格子矩阵,左下角的格子是起点,右上角的格子是大门。每个孩子每秒可以走向 上、下、左、右 前进一个格子,每个格子只能经过一次。但矩阵中间有一些障碍区,不能通过,只能绕过。”

例如,4×44×4 的矩阵,格子 (1,1),(2,3),(4,2)(1,1),(2,3),(4,2) 为障碍区,黑格子就是一条可行的路线。时间为 77。

输入格式

第一行为两个整数 𝑛,𝑚n,m。

第二至第 𝑚+1m+1 行里,每行描述一个障碍区。用两个整数表示 𝑥,𝑦x,y。

输出格式

仅一行,那个最大的时间差。

#include <bits/stdc++.h>
using namespace std;
const int maxn=114514;
struct point{
	int nt,stat,maxx,minx;
}a[2][2<<12];
int n,i,j,k,m,now=0,maxx=-0x7fffffff,minx=0x7fffffff,x,y;
int nxt[maxn];
int cnt[2];
bool flag[15][15];
void insert(int stat,int maxx,int minx){
	int tmp=stat%maxn;
	for(int i=nxt[tmp];i;i=a[now][i].nt)
	  if(a[now][i].stat==stat){
		a[now][i].maxx=max(a[now][i].maxx,maxx);
		a[now][i].minx=min(a[now][i].minx,minx);
		return ;
	  }
	a[now][++cnt[now]].stat=stat;
	a[now][cnt[now]].maxx=maxx;
	a[now][cnt[now]].minx=minx;
	a[now][cnt[now]].nt=nxt[tmp];
	nxt[tmp]=cnt[now];
}//hash
int main() {
	memset(flag,false,sizeof(flag));
    scanf("%d%d",&n,&m);
    for(i=1;i<=n+2;i++)
      for(j=1;j<=n+2;j++)
        flag[i][j]=true;
    for(i=1;i<=m;i++){
    	scanf("%d%d",&x,&y);
    	flag[x+2][y+2]=false;
	}
	for(i=2;i<=n+1;i++)
	  flag[i][2]=flag[2][i]=false;
	insert(0,0,0);
	for(i=n+2;i>=1;i--){
		for(j=1;j<=cnt[now];j++){
			a[now][j].stat<<=2;
		}
		for(j=1;j<=n+2;j++){
	  	    int pre=now;now^=1;cnt[now]=0;
	  	    memset(nxt,0,sizeof(nxt));
	  	    for(k=1;k<=cnt[pre];k++){
	  	    	int tmp1=(a[pre][k].stat>>(2*j-2))%4,tmp2=(a[pre][k].stat>>(2*j))%4;
	  	    	if(flag[i][j]==false){
	  	    		if(tmp1==0 && tmp2==0){
	  	    			insert(a[pre][k].stat,a[pre][k].maxx,a[pre][k].minx);
					}
				}
				else{
					if(tmp1==0 && tmp2==0){
						if(flag[i][j+1]==true && flag[i-1][j]==true) insert(a[pre][k].stat+(1<<(2*j-2))+(2<<(2*j)),a[pre][k].maxx+1,a[pre][k].minx+1);
						if(i!=n+2 || j!=1)insert(a[pre][k].stat,a[pre][k].maxx,a[pre][k].minx);
					}
					if(tmp1>0 && tmp2==0){
						if(flag[i][j+1]==true) insert(a[pre][k].stat-(tmp1<<(2*j-2))+(tmp1<<(2*j)),a[pre][k].maxx+1,a[pre][k].minx+1);
						if(flag[i-1][j]==true) insert(a[pre][k].stat,a[pre][k].maxx+1,a[pre][k].minx+1);
					}
					if(tmp1==0 && tmp2>0){
						if(flag[i][j+1]==true) insert(a[pre][k].stat,a[pre][k].maxx+1,a[pre][k].minx+1);
						if(flag[i-1][j]==true) insert(a[pre][k].stat-(tmp2<<(2*j))+(tmp2<<(2*j-2)),a[pre][k].maxx+1,a[pre][k].minx+1);
					}
					if(tmp1==1 && tmp2==2){
						if(i==1 && j==n+2){
							maxx=max(maxx,a[pre][k].maxx);
							minx=min(minx,a[pre][k].minx);
						}
					}
					if(tmp1==1 && tmp2==1){
						int count=1;
						for(int num=j+1;num<=n+2;num++){
							if((a[pre][k].stat>>(num*2))%4==1) count++;
							if((a[pre][k].stat>>(num*2))%4==2) count--;
							if(count==0){
								insert(a[pre][k].stat-(1<<(2*j-2))-(1<<(2*j))-(1<<(2*num)),a[pre][k].maxx+1,a[pre][k].minx+1);
								break;
							}
						}
					}
					if(tmp1==2 && tmp2==2){
						int count=1;
						for(int num=j-2;num>=0;num--){
							if((a[pre][k].stat>>(num*2))%4==1) count--;
							if((a[pre][k].stat>>(num*2))%4==2) count++;
							if(count==0){
								insert(a[pre][k].stat-(2<<(2*j-2))-(2<<(2*j))+(1<<(2*num)),a[pre][k].maxx+1,a[pre][k].minx+1);
								break;
							}
						}
					}
					if(tmp1==2 && tmp2==1) insert(a[pre][k].stat-(2<<(2*j-2))-(1<<(2*j)),a[pre][k].maxx+1,a[pre][k].minx+1);
				}
			  }
	    }
	}
	printf("%d",maxx-minx);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值