【搜索模拟】
【搜索模拟】
搜索+大模拟
DFS模拟
像素放置
https://www.lanqiao.cn/problems/3508/learning/
注意搜索中的遍历方式
注意特别处理 x=1 和 y=1
/*
【结论】
当(x,y)被遍历到后,(x-1,y-1)已经确定->需要check
如果是最后一列:(x-1,y)也确定了
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=15;
char s[N][N];
int ans[N][N];
int n,m;
bool check(int x,int y){
if(s[x][y]=='_') return true;
int cnt=0;
int res=s[x][y]-'0';
for(int i=-1;i<=1;i++){
for(int j=-1;j<=1;j++){
int nx=x+i,ny=y+j;
if(nx>=1 && nx<=n && ny>=1 && ny<=m){
if(ans[nx][ny]) cnt++;
}
}
}
if(cnt==res) return true;
else return false;
}
//设完回溯
void dfs(int x,int y){
//搜索出口:x搜完已经溢出
if(x==(n+1)){
for(int i=1;i<=m;i++){
if(!check(n,i)){
return;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cout<<ans[i][j];
}
cout<<endl;
}
return;
}
//换行
if(y==m){
ans[x][y]=1;
//只有一列
if(x==1 || (y==1 && check(x-1,y)) || (check(x-1,y-1) && check(x-1,y))) dfs(x+1,1);
ans[x][y]=0;
if(x==1 || (y==1 && check(x-1,y)) || (check(x-1,y-1) && check(x-1,y))) dfs(x+1,1);
}
else{
ans[x][y]=1;
if(x==1 || y==1 || check(x-1,y-1)) dfs(x,y+1);
ans[x][y]=0;
if(x==1 || y==1 || check(x-1,y-1)) dfs(x,y+1);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>s[i][j];
}
}
dfs(1,1);
return 0;
}
新婚
https://ac.nowcoder.com/acm/contest/114593/E
题目大意
从根节点到每个叶节点的每条链,每个节点的值拼成一个二进制串,每个子串转为十进制,问每个数存不存在
注意到

思路
dfs模拟一遍找链
因为数字的二进制位数最多为21 可以直接预处理出树上所有的*长度小于21*的链所代表的数字
dfs时用一个*栈*维护每个节点的数字
代码
const int N=1e5+10;
int n,q;
bool num[(1<<21)+10];
string s;
vector<int> g[N];
string t;//用栈维护子串
void dfs(int u,int fa){
t.push_back(s[u-1]);
int lb=max(0,(int)(t.size())-21);
for(int i=t.size()-1;i>=lb;i--){
string p=t.substr(i);//提取i到末尾的子串
num[stoi(p,0,2)]=1;
reverse(p.begin(),p.end());
num[stoi(p,0,2)]=1;
}
for(auto son:g[u]){
if(son!=fa){
dfs(son,u);
}
}
t.pop_back();//一条链找完了把子树出栈找另一个子树
}
void solve(){
cin>>n>>q;
cin>>s;
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,-1);
while(q--){
int x;
cin>>x;
if(num[x]) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
BFS模拟
推箱子
注意代码细节:
(1)回溯路径
(2)记录路径移动的简洁性
https://ac.nowcoder.com/acm/contest/108301/I
题目大意

思路
不要傻傻的存状态模拟!
分析一下题目,有显然结论:
(1)一个连通区域:目标数和箱子数一定是一样的
(2)一个箱子路过一个箱子:可以视为推新的箱子->可以视为经过

代码
const int N=55;
int n,m;
string s[N];
//路径回溯
int dist[N][N];
PII pre[N][N];
//目标位置
int px=-1,py=-1;
vector<pair<PII,PII>> ans;
//临时记路径
vector<PII> path;
char dir(PII x,PII y){
if(y.fi==x.fi+1) return 'D';
else if(y.fi==x.fi-1) return 'U';
else if(y.sc==x.sc+1) return 'R';
else if(y.sc==x.sc-1) return 'L';
assert(0);
}
void bfs(int x,int y){
memset(dist,0x3f,sizeof dist);
queue<PII> q;
q.push({x,y});
dist[x][y]=0;
px=-1;py=-1;
path.clear();
while(q.size()){
auto t=q.front();
q.pop();
if(s[t.fi][t.sc]=='*'){
px=t.fi;py=t.sc;
int tx=px,ty=py;
//回溯路线
while(1){
path.push_back({tx,ty});
if(dist[tx][ty]==0) break;
//更新要同时更新!
tie(tx,ty)=pre[tx][ty];
}
return;
}
for(int k=0;k<4;k++){
int nx=t.fi+dx[k],ny=t.sc+dy[k];
if(nx<0 || nx>=n || ny<0 || ny>=m) continue;
if(s[nx][ny]=='#') continue;
if(dist[nx][ny]==inf_int){
dist[nx][ny]=dist[t.fi][t.sc]+1;
pre[nx][ny]=t;
q.push({nx,ny});
}
}
}
}
void path_save(){
//一条路上不管! @ 那么如果路径上遇到了箱子要让箱子先推
int now=0;
int len_path=path.size();
//注意这里终点不存:
for(int i=1;i<len_path;i++){
if(s[path[i].fi][path[i].sc]!='.'){
//path是倒着存的:记录的时候要倒过来
for(int j=i;j>now;j--){
ans.push_back({path[j],path[j-1]});
}
now=i;
}
}
//注意更新地图状态:原来的起始点设成空地,原来的目标点设成(!)
s[path.back().fi][path.back().sc]='.';
s[path[0].fi][path[0].sc]='!';
}
void solve(){
cin>>n>>m;
for(int i=0;i<n;i++) cin>>s[i];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(s[i][j]=='@'){
bfs(i,j);
if(px==-1){
cout<<-1<<endl;
return;
}
path_save();
}
}
}
cout<<ans.size()<<endl;
for(auto [key,val]:ans){
cout<<key.fi+1<<" "<<key.sc+1<<" "<<dir(key,val)<<endl;
}
}

浙公网安备 33010602011771号