zoukankan      html  css  js  c++  java
  • 6493. 【GDOI2020模拟03.04】迷宫

    题目描述


    题解

    da☆ze

    人类智慧题

    假如当前可能所在的集合为S,等价于以光速在每个可能的房间之间来回闪现

    题目中的门是不同的,并且人物也能够看出具体是ABCD中的那扇门,但是不能通过门看到走到的房间情况,可以当成传送门

    假设走入A门,根据所在具体房间的不同可能从ABCD四种门中走出,那么便可以判断出当前所在的集合

    设S[i][j]表示当前从i门走入会走出门j的集合,f[s]表示可能集合为s的答案

    那么当前的答案=min(max(f[S[A][A]],...,f[S[A][D]]),...,max(f[S[D][A]],...,f[S[D][D]]))+1

    因为题目所求的是最坏条件,所以走进每个门都会走到最坏的集合中,答案即为最坏条件下最好的选择

    发现每次只+1,所以可以直接bfs拓扑

    因为答案只可能变大,如果一个max里面的四个集合都算出来了,那么便可以得到当前的答案

    关于bfs能走到所有状态的证明:

    设S中1的个数为层数,对于同一层必然会有一个靠近0点的状态,使得一个max内必然有一个状态在下一层

    而又因为一种走法对应的四个状态无交,所以其余三个状态要么不存在要么也在下一层,因此一定可以从下一层推到上一层

    会卡时间,把0点删掉变成2^(n-1)即可

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define ll long long
    #define file
    using namespace std;
    
    int a[8388609][3],ls[524288],p[21],b[21][4],B[21][4],c[524288][4],s[4][4],d[524288],f[524288],n,Q,i,j,k,l,x,y,len,L,h,t;
    
    void New(int x,int y,int z)
    {
    	++len;
    	a[len][0]=y;
    	a[len][1]=ls[x];
    	ls[x]=len;
    	a[len][2]=z;
    	
    	++c[y][z];
    }
    
    char gc()
    {
    	char ch;
    	
    	ch=getchar();
    	while (ch<'A' || ch>'D')
    	ch=getchar();
    	
    	return ch-'A';
    }
    
    int main()
    {
    	freopen("maze.in","r",stdin);
    	#ifdef file
    	freopen("maze.out","w",stdout);
    	#endif
    	
    	p[1]=1;
    	fo(i,2,20)
    	p[i]=p[i-1]*2;
    	
    	scanf("%d%d",&n,&Q);L=p[n]-1;
    	fo(i,1,n+n)
    	{
    		scanf("%d",&x);k=gc();
    		scanf("%d",&y);l=gc();
    		
    		b[x][k]=y;B[x][k]=l;
    		b[y][l]=x;B[y][l]=k;
    	}
    	
    //	---
    	
    	fo(i,1,L)
    	{
    		memset(s,0,sizeof(s));
    		
    		fo(j,1,n-1)
    		if (i&p[j])
    		{
    			fo(k,0,3)
    			s[k][B[j][k]]^=p[b[j][k]];
    		}
    		
    		fo(j,0,3)
    		{
    			fo(k,0,3)
    			New(s[j][k],i,j);
    		}
    	}
    	
    //	---
    	
    	h=0;t=1;
    	d[1]=0;f[0]=1;
    	while (h<t)
    	{
    		for (i=ls[d[++h]]; i; i=a[i][1])
    		if (!f[a[i][0]] && !(--c[a[i][0]][a[i][2]]))
    		{
    			f[a[i][0]]=f[d[h]]+1;
    			d[++t]=a[i][0];
    		}
    	}
    	
    //	---
    	
    	for (;Q;--Q)
    	{
    		scanf("%d",&x);
    		printf("%d
    ",f[x>>1]);
    	}
    	
    	fclose(stdin);
    	fclose(stdout);
    	
    	return 0;
    }
    
  • 相关阅读:
    Android开发中常见的错误
    使用命令行的方式向GitHub中上传本地项目
    jmeter保存测试结果到文件
    转 Jmeter参数化的4种方法
    键盘各键对应的编码值(key)
    CacheHelper对缓存的控制
    Oracle存储过程
    Oricle中SQL语法
    python学习资料百度网盘分享
    一些网站学习的链接
  • 原文地址:https://www.cnblogs.com/gmh77/p/12432026.html
Copyright © 2011-2022 走看看