目录
1 连通性问题(内部搜索)
内部搜索一般不用恢复现场
1.迷宫
信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)
#include<bits/stdc++.h>
using namespace std;
const int N=110;
char g[N][N];
int sx,sy,ex,ey;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
bool st[N][N];
int n;
bool dfs(int x,int y)
{
if(g[x][y]=='#') return false;//假如是障碍
if(x==ex&&y==ey) return true;//假如是终点了
st[x][y]=true;//标记这个点走过
for(int i=0;i<4;i++)//枚举四个方向
{
int a=x+dx[i],b=y+dy[i];
if(a<0||a>=n||b<0||b>=n) continue;//越界
if(st[a][b]) continue;//走过
if(dfs(a,b)) return true;//假如后面能走到
}
return false;//反之走不到
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n;
memset(st,0,sizeof st);//清空上一层状态
for(int i=0;i<n;i++) cin>>g[i];
cin>>sx>>sy>>ex>>ey;
if(dfs(sx,sy)) puts("YES");//假如能走到
else puts("NO");
}
return 0;
}
2.红与黑
信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)
#include<bits/stdc++.h>
using namespace std;
const int N=25;
int n,m,cnt;
char g[N][N];
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
bool st[N][N];
void dfs(int x,int y)
{
st[x][y]=true;//标记走过
for(int i=0;i<4;i++)
{
int a=x+dx[i],b=y+dy[i];
if(a<0||a>=n||b<0||b>=m) continue;//越界
if(st[a][b]||g[a][b]!='.') continue;//假如走过或者不能走的
cnt++;//连通数增加
dfs(a,b);
}
}
int main()
{
while(cin>>m>>n,n||m)
{
memset(st,0,sizeof st);//清空上一层状态
for(int i=0;i<n;i++) cin>>g[i];
int x,y;
for(int i=0;i<n;i++)//找起点
for(int j=0;j<m;j++)
if(g[i][j]=='@')
{
x=i,y=j;
break;
}
cnt=1;//自己起点是一个点
dfs(x,y);//找一下联通多少个
cout<<cnt<<endl;//输出个数
}
return 0;
}
2.搜索顺序(外部搜索)
外部搜索一般要恢复现场
1.马走日
信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)
#include<bits/stdc++.h>
using namespace std;
const int N=15;
int n,m,sx,sy,cnt=1,ans;
bool st[N][N];
int dx[8]={-2,-1,1,2,2,1,-1,-2},dy[8]={1,2,2,1,-1,-2,-2,-1};
void dfs(int x,int y)
{
if(cnt==n*m)//假如走完所有点
{
ans++;//方案加1
return;
}
st[x][y]=true;//标记这个点走过
for(int i=0;i<8;i++)//枚举八个方向
{
int a=x+dx[i],b=y+dy[i];
if(a<0||a>=n||b<0||b>=m) continue;//越界
if(st[a][b]) continue;//走过
cnt++;//步数+1
dfs(a,b);
cnt--;//恢复现场步数-1
}
st[x][y]=false;//恢复现场
}
int main()
{
int T;
cin>>T;
while(T--)
{
ans=0;
cin>>n>>m>>sx>>sy;
dfs(sx,sy);
cout<<ans<<endl;
}
return 0;
}
2.单词接龙
信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)
#include<bits/stdc++.h>
using namespace std;
const int N=25;
string word[N];
int g[N][N],ans=0;
int used[N];
int n;
void dfs(string dragon,int u)
{
ans=max(ans,(int)dragon.size());//取一次龙的最长度
used[u]++;//该位置使用加1
for(int i=0;i<n;i++)
if(g[u][i]&&used[i]<2)//枚举看看能不能接到该字符串后面
dfs(dragon+word[i].substr(g[u][i]),i);
used[u]--;//恢复现场
}
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>word[i];
char start;//龙的开头
cin>>start;
for(int i=0;i<n;i++)//用来判断那两个可以接到一起
for(int j=0;j<n;j++)
{
string a1=word[i],a2=word[j];
for(int k=1;k<min(a1.size(),a2.size());k++)//从小开始搜看能不能接,接的越少龙越长
if(a1.substr(a1.size()-k,k)==a2.substr(0,k))
{
g[i][j]=k;
break;
}
}
for(int i=0;i<n;i++)
if(word[i][0]==start)//假如符合龙的开头
dfs(word[i],i);
cout<<ans<<endl;
return 0;
}
3.分成互质组
信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)
#include<bits/stdc++.h>
using namespace std;
const int N=15;
int p[N],n,ans=10;
bool st[N];
int group[N][N];
int gcd(int a,int b)//用来求最小公倍数,假如最小公倍数大于1说明不互质,反之互质
{
return b?gcd(b,a%b):a;
}
bool check(int g[],int gc,int u)
{
for(int i=0;i<gc;i++)//判断该组的所有元素是否与该元素互质
if(gcd(p[g[i]],p[u])>1)//假如不互质
return false;
return true;//反之互质
}
void dfs(int g,int gc,int cnt,int start)//表示有多少组,该组有多少个元素,已用元素个数,已经用到第几个元素
{
if(g>=ans) return;//假如组数已经大于ans,则没必要更新了
if(cnt==n) ans=g;//g已经是最小值了,假如大于ans已经在上一步弹掉了
int flag=true;//用来标记是否需要新开一组
for(int i=start;i<n;i++)//找后面的元素是否能假如该组
if(!st[i]&&check(group[g],gc,i))//假如可以加
{
st[i]=true;//标记该元素已经用过了
group[g][gc]=i;//该组第gc的元素就是他
dfs(g,gc+1,cnt+1,i+1);//下一步是组数不变,元素加1,已用元素加1,从下一个元素开始
st[i]=false;//恢复现场
flag=false;//说明不用新开组
}
if(flag) dfs(g+1,0,cnt,0);//假如新开组,则组数加1,元素0个,已用cnt个,下标从0开始,因为该组是没有元素的
}
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>p[i];
dfs(1,0,0,0);//从一组开始,该组的元素0个,已用元素0个,元素从0开始
cout<<ans<<endl;
return 0;
}