• 【洛谷T7243】【CJOJ2225】【BYVoid S3】珠光宝气阁(潜入辛迪加)


    Description

    “我们最新的研究成果《毒药研究方案》被可恶的辛迪加偷走了!”作为拉文霍德的一员,你一定感到很震惊,因为它是我们最尖端的科研人员的一年的研究成果。被辛迪加获得,我们可能会有灭顶之灾。

    狡猾的辛迪加为了躲避我们的追杀,他们并没有把《毒药研究方 案》带回激流堡,而是把它藏了起来。但是终究是我们技高一筹,运用侏儒的最新研究成果“静电放射探测器”,我们已经发现了他们的藏身之地。原来他们早就在 奥特兰克山脉的地下修建了一个巨大的城市,现在,他们就把《毒药研究方案》放在了城市的最深处。更好的消息是,我们已经发现了地下城的入口。

    作为一名出色的盗贼,你要学会以彼之道,还施彼身——把《毒药研究方案》偷回来。然而辛迪加布置了严密的防御,更糟糕的是,他们从地精购买了电磁监视器。无论你的潜行技巧有多么高明,只要一接近它,就会出发警报。只有破坏它的供电系统,才能电磁监视器悄无声息得失效。

    现在,“静电放射探测器”已经为我们生成了一张地图,它可以告诉你整个地下城的布局结构,包括每一个电磁监视器的位置,及其供电装置的位置。辛迪加的地下城可以被描述为一个N*N的表格,城市的入口在(1,1)处,目标《毒药研究方案》在(N,N)处。每个单元格可能是一片空地、一个障碍物、一个辛迪加卫士、一个电磁监视器、或者一个的供电装置。

    从入口处开始,每步你只能上、下、左、右移动到相邻的一个单元 格,不可以停留在原地。你只能进入空地,或者失去供电系统的电磁监视器的位置,或者摧毁供电装置。你不能移动到障碍物上,也不能进入辛迪加卫士的视线中。 辛迪加卫士可以监视自己所在单元格以及上下左右共五格的位置,而且他们的视线可以重叠。你不能杀死辛迪加卫士,也不能被他们发现。每个电磁监视器的供电装 置可能存在,也可能无法破坏或者根本不存在。一个供电装置也可能会对应零个、一个或多个电磁监视器,意味着摧毁它,对应的所有电磁监视器都会失效。(1,1)和(N,N)一定是可以通行的。

    拉文霍德要求你在执行任务之前首先给出一个计划书,即要求算出至少一共需要多少步,才能拿到我们的《毒药研究方案》。

    Input

    第1行,两个整数N, M。表示地图大小为N * N,供电装置的数量为M。
    第2-N+1行,每行N个整数,每个整数i可能是0,-1,-2或者一个正整数。i=0表示该位置为一块空地,i=-1表示该位置为一个障碍物,i=-2表示该位置为一个辛迪加卫士。如果i是一个属于[1,M]的正整数,则表示该位置为一个供电装置,其编号为i。如果i是一个大于M的正整数,则表示该位置为一个电磁监视器,它的电力由编号为i-M的供电装置提供。

    Output

    一个整数,为拿到《毒药研究方案》所需的最少的步数。如果不能到达输出-1.

    Sample Input

    6 2
    0 0 0 -2 -1 2
    -1 0 0 0 -1 0
    -2 0 0 0 3 3
    -2 0 0 -1 -1 4
    0 -1 0 0 -1 0
    1 0 0 0 -1 0

    Sample Output

    24

    Hint

    样例说明
    地图如下图,S为入口,T为目标,黑色的单元格为障碍物。每个E表示一个卫兵,(E)为卫兵的监视范围。K1表示供电装置1,K2表示供电装置2。D1表示供电装置为1的电磁监视器,D2表示供电装置为2的电磁监视器。

    最优的路线为(1,1) →(1,2) →(2,2) →(2,3) →(3,3) →(4,3) →(5,3) →(6,3) →(6,2) →(6,1)(破坏供电1) →(6,2) →(6,3) →(5,3) →(4,3) →(3,3) →(3,4) →(3,5) →(3,6) →(2,6) →(1,6)(破坏供电2) →(2,6) →(3,6) →(4.6) →(5,6) →(6,6)

    这里写图片描述

    数据规模

    这道题目的空间限制是512MB
    对于15%数据
    M=0

    对于40%数据
    M<=2

    对于100%数据
    2<=N<=50
    0<=M<=16

    题解

    搜索的好题!

    首先,从简单的条件开始逐步考虑

    对于每一个守卫而言,直接把他的上下左右四个方格置为障碍物即可(这里注意一点,如果存在几个守卫连着站在一起要注意一下怎么赋值!!!)

    守卫的问题解决完了

    如何处理电磁监视器和供电呢?

    观察数据范围,供电的数量小于16
    那么,我们可以使用状态压缩
    对于供电装置的破坏和地图的走动关系
    开一个50 * 50 * 65536的数组
    (内存有512MB,这样开内存是足够的)
    那么,对于当前的每一种状态,直接进行BFS就行了
    但是这里的细节比较多,需要自己在实现程序的时候注意一下。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<algorithm>
    using namespace std;
    
    inline int read()
    {
    	register int x=0,t=1;
    	register char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-'){t=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
    	return x*t;
    }
    
    struct Node
    {
    	  int x,y;//位置
     	  int st;//步数
    	  int t;//状态 
    };
    
    queue<Node> Q;//队列 
    
    int d[4][2]={1,0,-1,0,0,1,0,-1};//方向 
    bool vis[60][60][65540];//存储位置信息 
    int g[101][101];//地图 
    int n,m,x,y,tt;
    
    int main()
    {
    	freopen("syndicate.in","r",stdin);
    	freopen("syndicate.out","w",stdout);
        
    	n=read();m=read();
        memset(g,-1,sizeof(g));//全部赋为障碍 
        for(register int i=1;i<=n;++i)
          for(register int j=1;j<=n;++j)
            g[i][j]=read();
            
        for(register int i=1;i<=n;++i)
          for(register int j=1;j<=n;++j)
            if(g[i][j]==-2)//如果是一个卫士 
              for(register int k=0;k<4;++k)
                if(g[i+d[k][0]][j+d[k][1]]!=-2)
                  g[i+d[k][0]][j+d[k][1]]=-1;//把上下左右都换成障碍(不用管其他的)
                
        if(g[1][1]==-1||g[n][n]==-1){cout<<-1<<endl;return 0;}
    	                //如果起点或终点就是障碍直接无解 
    	                
    	Q.push((Node){1,1,0,0});//放入头结点 
    	
        while(!Q.empty())//广搜  
        {
        	    Node now=Q.front();//取出头结点  
        	    Q.pop();
        	    
        	    for(register int i=0;i<4;++i)//移动 
        	    {
        	    	    x=now.x+d[i][0];
        	    	    y=now.y+d[i][1];
        	    	    
        	    	    if(!vis[x][y][now.t])//当前结点没有拓展过 
        	    	    {
        	    	    	      vis[x][y][now.t]=true;//标记为拓展过 
        	    	    	      if(g[x][y]==-1||g[x][y]==-2)continue;//不能够是障碍
    							   
        	    	    	      if(g[x][y]>m)
    							        //如果当前位置是监视器
    							  {
    							  	       if(now.t&(1<<(g[x][y]-1-m)))//供电已经被破坏
    							  	          Q.push((Node){x,y,now.st+1,now.t});//可以过去 
    							  	       else
    							  	          continue;//不能过去 
    						      }
    						      
    						      else
    						      if(g[x][y]<=m&&g[x][y]>=1)
    							           //如果是一个供电装置
    							  {
    							  	       if(!(now.t&(1<<(g[x][y]-1))))//没有被破坏
    							  	       {
    								  	       tt=now.t|(1<<(g[x][y]-1));
    								  	       vis[x][y][tt]=true;
    								  	       Q.push((Node){x,y,now.st+1,tt});
    							  	       	   //标记为破坏并且放入队列 
    							  	       }
    							  	       else//被破坏,可以当做空地走
    									   	    Q.push((Node){x,y,now.st+1,now.t});
    						      }
    						      
    						      else
    						      if(g[x][y]==0)
    						               //如果是空地
    							  {
    							  	       Q.push((Node){x,y,now.st+1,now.t});
    							  }
    							  
    							  if(x==n&&y==n)//到达了终点
    							  {
    							  	       //直接输出结果  
    							  	       cout<<now.st+1<<endl;
    							  	       return 0;
    						      }
        	    	    }
        	    }
        }
        
        cout<<-1<<endl;//无法到达
        
    	return 0; 
    	
    }
    
    
  • 相关阅读:
    nexus配置yum私有仓库
    通过Kubeadm升级Kubernetes集群
    K8s容器网络如何实现通信?
    文件与目录的默认权限与隐藏权限(转)
    ”十六“进制查看器(转)
    常用的文件和目录操作命令(转)
    改变文件属性与权限(转)
    Linux目录规范和含义(转)
    文件的属性
    所有者,群组,其他人
  • 原文地址:https://www.cnblogs.com/cjyyb/p/7197287.html
Copyright © 2020-2023  润新知