记忆化搜索
题目地址:acwing
题目大意:
你是一个可以控制风的神仙。
通过把云吹到不同的位置,你可以控制降雨。
云下地区会降雨,没有云的地方阳光灿烂。
你是一个仁慈的神,希望土地在平时可以有足够的雨水,在赶集和过节能够充满阳光。
你负责掌控一个村子的天气状况。
这个村子呈4 x 4的网格状分布,村子内的每个区域被编号如下图所示:
你拥有一片2 x 2大小的云,这片云不能到村子以外的地方。
你将获得一段时间内村子每个区域的赶集和过节时间表。
在这段时间的第一天,中部地区(6-7-10-11)将会下雨。
在接下来的每一天中,您可以在四个基本方向(东南西北)之中选取一个方向,将云移动1或2个方格,或将其保持在相同位置。
不允许对角线移动,所有动作都在一天开始时发生。
任何地区都不能连续七天或以上时间都不降雨。
这段时间以外的日子的下雨状况你无需做任何考虑。
题目思路:暴力搜索+记忆化
要注意的地方就是如何能判断一个地方是否有7天连续不下雨,但是通过分析我们可以得出四个角下雨一定能够保证所在的四方格里的村庄都下雨,所以我们只需要判断四个角是不是连续7天不下雨就行了,反证法就是只要四个角七天内下雨那么一定能保证所有的村庄连续不下雨的天数都不会超过7天
代码如下(看了yxc的题解视频):
#include <iostream> #include <cstring> #include <queue> using namespace std; const int N = 366; int st[N][4][4]; int f[N][3][3][7][7][7][7]; struct node{ int day,x,y,s1,s2,s3,s4; }; int dx[5]={-1,0,1,0,0}; int dy[5]={0,1,0,-1,0}; int n; int bfs(){ memset(f,0,sizeof f); if(st[1][1][1]||st[1][1][2]||st[1][2][1]||st[1][2][2])return 0; f[1][1][1][1][1][1][1]=1; queue<node> q; q.push({1,1,1,1,1,1,1}); while(q.size()){ auto t=q.front(); q.pop(); if(t.day==n)return 1; for(int i=0;i<5;i++){ for(int j=1;j<=2;j++){ int s1=t.s1,s2=t.s2,s3=t.s3,s4=t.s4; int nx=t.x+dx[i]*j,ny=t.y+dy[i]*j; if(nx<0||nx>2||ny<0||ny>2)continue; auto& sti=st[t.day+1]; if(sti[nx][ny]||sti[nx+1][ny]||sti[nx][ny+1]||sti[nx+1][ny+1])continue; if(nx==0&&ny==0){ s1=0; } else if(++s1==7)continue; if(nx==0&&ny==2){ s2=0; } else if(++s2==7)continue; if(nx==2&&ny==0){ s3=0; } else if(++s3==7)continue; if(nx==2&&ny==2){ s4=0; } else if(++s4==7)continue; if(f[t.day+1][nx][ny][s1][s2][s3][s4])continue; f[t.day+1][nx][ny][s1][s2][s3][s4]=1; q.push({t.day+1,nx,ny,s1,s2,s3,s4}); } } } return 0; } int main(){ while(cin>>n&&n){ for(int i=1;i<=n;i++){ for(int j=0;j<4;j++){ for(int k=0;k<4;k++){ cin>>st[i][j][k]; } } } cout<<bfs()<<endl; } }
思路并不难,就是要减去一些无效状态和记忆化的状态,(也可以用dfs写,dp写)