zoukankan      html  css  js  c++  java
  • 「Luogu P2845 [USACO15DEC]Switching on the Lights 开关灯」

    USACO的又一道搜索题

    前置芝士

    1. BFS(DFS)遍历:用来搜索.(因为BFS好写,本文以BFS为准还不是因为作者懒)
    2. 链式前向星,本题的数据比较水,所以邻接表也可以写,但是链式前向星它不香吗.

    具体做法

    对于一个点,它可能有不止一个房间,虽然可以开一个([x_1][y_1][x_2][y_2])邻接矩阵,但是每次查询时需要( heta(N^2))枚举,十分的麻烦,还可能会T,这时就需要用到链式前向星来优化了,不仅优化了时间,还优化了空间,简直一举两得.这里的链式前向星的写法也很简单:

    代码

    struct Edge//定义一个结构体
    {
    	int next;
    	int x,y;
    }edge[maxM];
    int cnt=0;
    int _head[maxN][maxN];
    void Add(Room a,Room b)//在房间a和房间b间添加一条边
    {
    	edge[++cnt].x=b.x;
    	edge[cnt].y=b.y;
    	edge[cnt].next=_head[a.x][a.y];
    	_head[a.x][a.y]=cnt;
    }
    //一时define一时爽,一直define一直爽
    #define For(x,y) for(int _i_=_head[x][y];_i_;_i_=edge[_i_].next)
    #define X edge[_i_].x
    #define Y edge[_i_].y
    

    对于每个点它只会进一次队列,但是如果那时它的灯没有打开,不代表这个灯永远不会被打开,所以在每进入一个房间后需要判断被打开灯的房间是否被询问过,如果被询问过需要将这个点放入队列.

    注意输出的是有多少个房间的灯可以被打开.

    有一些具体的细节讲.

    代码

    #include<bits/stdc++.h>
    #define rap(i,first,last) for(int i=first;i<=last;++i)
    using namespace std;
    const int maxN=105;
    const int maxM=1e6+5;
    const int move_x[5]={233,1,-1,0,0};
    const int move_y[5]={233,0,0,1,-1};
    int head=0,tail=1;
    bool visit[maxN][maxN];
    struct Que//队列
    {
    	int x;
    	int y;
    }que[maxN*maxN];//队列里最多N^2个房间,每个房间只会进一次
    int N,M;
    struct Room//对于房间再开一个结构体
    {
    	int x,y;
    };
    //链式前向星
    struct Edge
    {
    	int next;
    	int x,y;
    }edge[maxM];
    int cnt=0;
    int _head[maxN][maxN];
    bool opened[maxN][maxN];
    void Add(Room a,Room b)
    {
    	edge[++cnt].x=b.x;
    	edge[cnt].y=b.y;
    	edge[cnt].next=_head[a.x][a.y];
    	_head[a.x][a.y]=cnt;
    }
    int answer=1;
    #define For(x,y) for(int _i_=_head[x][y];_i_;_i_=edge[_i_].next)
    #define X edge[_i_].x
    #define Y edge[_i_].y
    //
    void Open(int x,int y)//打开一个房间的开关
    {
    	For(x,y)
    	if(!opened[X][Y])//注意要有这个特判
    	{
    		opened[X][Y]=1;
    		answer++;//每打开一个灯answer++
    		if(visit[X][Y])//如果询问过就放入队列
    		{
    			que[++tail].x=X;
    			que[tail].y=Y;
    		}
    	}
    }
    int main()
    {
    	scanf("%d%d",&N,&M);
    	Room room1,room2;
    	rap(i,1,M)
    	{
    		scanf("%d%d%d%d",&room1.x,&room1.y,&room2.x,&room2.y);
    		Add(room1,room2);//添加一条边
    	}
    	rap(i,1,N)visit[i][0]=visit[0][i]=visit[N+1][i]=visit[i][N+1]=1;//在四周打上标记
    	que[1].x=1;
    	que[1].y=1;
    	opened[1][1]=1;
    	while(++head<=tail)
    	{
    		Open(que[head].x,que[head].y);//在队头时打开比较方便,不会有遗漏
    		rap(i,1,4)
    		if(opened[que[head].x+move_x[i]][que[head].y+move_y[i]])//如果这个位置的灯被打开了
    		{
    			if(!visit[que[head].x+move_x[i]][que[head].y+move_y[i]])//没有询问过就放入队列
    			{
    				visit[que[head].x+move_x[i]][que[head].y+move_y[i]]=1;
    				que[++tail].x=que[head].x+move_x[i];
    				que[tail].y=que[head].y+move_y[i];
    			}
    		}
    		else
    		{
    			visit[que[head].x+move_x[i]][que[head].y+move_y[i]]=1;//没有被打开也要标记为询问过
    		}
    	}
    	printf("%d",answer);//输出answer
    	return 0;
    }
    
  • 相关阅读:
    Java实现蓝桥杯算法提高12-2扑克排序
    Java实现蓝桥杯算法提高12-2扑克排序
    Java实现蓝桥杯算法提高12-2扑克排序
    Java实现N*N矩阵旋转(360度)
    Java实现N*N矩阵旋转(360度)
    Java实现N*N矩阵旋转(360度)
    Java实现ACMGoShopping
    linux 远程桌面工具NX
    windows下用vs2010编译ffmpeg
    在Windows下编译ffmpeg完全手册
  • 原文地址:https://www.cnblogs.com/Sxy_Limit/p/12169452.html
Copyright © 2011-2022 走看看