终于,做完了kuangbin大神带你飞的专题一之简单搜索,实在有一股无法言喻的感觉,每道题类型都差不多但细节实现却有点细微区别,所以14道题我就只当作5题了。。
棋盘问题
稍微变了点形的皇后问题,不能一行一行搜索,要一个一个格子搜索
include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=10;
int n,k,ans;
int R[N],C[N],a[N][N];
char ch;
void dfs(int row,int col,int num){
int NR,NC;
if (num==k+1) {
ans++;
return;
}
if(row!=n){
NC=col+1;
NR=row;
if (NC==n) {
NC=0;
NR++;
}
if(!a[row][col]&&!R[row]&&!C[col]){
R[row]=1;
C[col]=1;
dfs(NR,NC,num+1);
C[col]=0;
R[row]=0;
dfs(NR,NC,num);
}
else dfs(NR,NC,num);
}
}
int main(){
while(cin>>n>>k){
if (n==-1&&k==-1) return 0;
ans=0;
memset(a,0,sizeof(a));
memset(R,0,sizeof(R));
memset(C,0,sizeof(C));
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>ch;
if (ch=='.'){
a[i][j]=1;
}
else if (ch=='#') {
a[i][j]=0;
}
}
}
dfs(0,0,1);
cout<<ans<<endl;
}
return 0;
}
Dungeon Master
三维BFS
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
const int N=30+10;
using namespace std;
struct state{
int z,x,y,step;
};
queue<state> Q;
set<int> S;
int L,R,C,goalx,goaly,goalz,X,Y,Z,code;
char tmp;
int dx[6]={1,-1,0,0,0,0},
dy[6]={0,0,1,-1,0,0},
dz[6]={0,0,0,0,1,-1};
int a[N][N][N];
void bfs(){
while(!Q.empty()){
state t=Q.front();Q.pop();
for(int i=0;i<6;i++){
X=t.x+dx[i];
Y=t.y+dy[i];
Z=t.z+dz[i];
if (a[Z][X][Y]==1||X<0||X>=R||Z<0||Z>=L||Y<0||Y>=C) continue;
code=10000*Z+100*X+Y;
if (X==goalx&&Y==goaly&&Z==goalz){
cout<<"Escaped in "<<t.step+1<<" minute(s)."<<endl;
return;
}
if (S.find(code)==S.end()){
S.insert(code);
state node={Z,X,Y,t.step+1};
Q.push(node);
}
}
}
cout<<"Trapped!"<<endl;
}
int main(){
while(cin>>L>>R>>C){
if (!L&&!R&&!C) break;
memset(a,0,sizeof(a));
S.clear();
while(!Q.empty()) Q.pop();
for(int i=0;i<L;i++){
for(int j=0;j<R;j++){
for(int k=0;k<C;k++){
cin>>tmp;
if(tmp=='S'){
state first={i,j,k,0};
Q.push(first);
code=10000*i+100*j+k;
S.insert(code);
a[i][j][k]=0;
}
else if(tmp=='E'){
goalz=i;
goalx=j;
goaly=k;
a[i][j][k]=0;
}
else if(tmp=='#'){
a[i][j][k]=1;
}
else if(tmp=='.'){
a[i][j][k]=0;
}
}
}
}
bfs();
}
return 0;
}
Catch That Cow
BFS,数字变换,反过来找,能稍微剪一下枝
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
#include <queue>
using namespace std;
struct node{
int num,step;
};
int n,k,T,Step;
int main(){
cin>>n>>k;
if (n==k){
cout<<0<<endl;
return 0;
}
queue<node> Q;
set<int> S;
node first={k,0};
Q.push(first);
S.insert(k);
while(!Q.empty()){
node t=Q.front();Q.pop();
for(int i=0;i<3;i++){
if (i==0) T=t.num+1;
else if (i==1) T=t.num-1;
else if ((i==2)&&(t.num%2==0)) T=t.num/2;
Step=t.step+1;
if (S.find(T)!=S.end()) continue;
if (T==n){
cout<<Step<<endl;
return 0;
}
node t1={T,Step};
Q.push(t1);
S.insert(T);
}
}
return 0;
}
Fliptile
二进制枚举,位运算,只用枚举第一行就能确定整个棋盘的翻转情况
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
const int N=20+10;
const int INF=0x3f3f3f3f;
using namespace std;
int dx[4]={0,0,-1,1},
dy[4]={-1,1,0,0};
int n,m,k,tmp,ok,ans=INF,cnt;
int a[N][N],vis[N][N],opr[N][N];
void turn(int x,int y){
int X,Y;
a[x][y]=a[x][y]^1;
for(int i=0;i<4;i++){
X=x+dx[i];
Y=y+dy[i];
if (X<0||X>=n||Y<0||Y>=m) continue;
a[X][Y]=a[X][Y]^1;
}
}
int check(int r){
for(int i=0;i<m;i++){
if (a[r][i]) return 0;
}
return 1;
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>a[i][j];
}
}
for(int i=0;i<=(1<<m)-1;i++){
cnt=0;
memset(vis,0,sizeof(vis));
for(int j=0;j<m;j++){
k=1<<j;
tmp=k&i;
if (tmp) {
vis[0][m-1-j]=1;
turn(0,m-1-j);
cnt++;
}
}
/*cout<<endl;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cout<<a[i][j]<<' ';
}
cout<<endl;
}*/
for(int i=1;i<n;i++){
for(int j=0;j<m;j++){
if (a[i-1][j]) {
turn(i,j);
vis[i][j]=1;
cnt++;
}
}
}
if (check(n-1)) {
if (cnt<ans){
ans=cnt;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
opr[i][j]=vis[i][j];
}
}
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if (vis[i][j]) turn(i,j);
}
}
}
if (ans==INF) cout<<"IMPOSSIBLE"<<endl;
else {
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cout<<opr[i][j]<<' ';
}
cout<<endl;
}
}
return 0;
}
Find The Multiple
依旧是反过来找,正难则反,深搜要自己限定深度,或用bfs
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
typedef unsigned long long ull;
typedef long long ll;
using namespace std;
int n,ok;
ull ans;
void ids(ull num,int k,int dep){
if (ok==1) return;
if (num%n==0) {
ans=num;
ok=1;
return;
}
if (k==dep) return;
ids(num*10,k+1,dep);
ids(num*10+1,k+1,dep);
}
int main(){
while(cin>>n){
if (!n) break;
ok=0;
ids(1,1,19);
if (ok) cout<<ans<<endl;
}
return 0;
}
Prime path
关键是数位的枚举
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
using namespace std;
const int N=10000+10;
struct node{
int num,step;
};
int t,n,m,tmp,Step,Num,number;
int prime[N];
void bfs(){
cin>>n>>m;
if (n==m){
cout<<0<<endl;
return;
}
queue<node> Q;
set<int> S;
node first={n,0};
Q.push(first);
S.insert(n);
while(!Q.empty()){
node t=Q.front();Q.pop();
for(int i=1;i<=1000;i*=10){
tmp=t.num / i % 10;
number=t.num-tmp*i;
Step=t.step+1;
for(int j=0;j<=9;j++){
Num=number+j*i;
//cout<<Num<<endl;
if (!prime[Num]||S.find(Num)!=S.end()||Num<1000) continue;
//cout<<Num<<endl;
if (Num==m){
cout<<Step<<endl;
return;
}
node t1={Num,Step};
Q.push(t1);
S.insert(Num);
}
}
}
}
int main(){
for(int i=2;i<=9999;i++) prime[i]=1;
for(int i=2;i<=9999;i++){
if (prime[i]){
for(int j=i*i;j<=9999;j+=i){
prime[j]=0;
}
}
}
cin>>t;
while(t--) bfs();
return 0;
}
Shuffle’m Up
模拟题,体会一下模拟与搜索的区别
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <string>
#include <set>
using namespace std;
int t,len,step,kase;
string s1,s2,s3;
set<string> S;
int main(){
cin>>t;
while(t--){
kase++;
cin>>len;
cin>>s1>>s2>>s3;
step=0;
while(1){
step++;
string tmp="";
for(int i=0;i<len;i++){
tmp+=s2[i];
tmp+=s1[i];
}
//cout<<tmp<<endl;
if (S.find(tmp)!=S.end()){
cout<<kase<<' '<<-1<<endl;
break;
}
S.insert(tmp);
if (tmp==s3) {
cout<<kase<<' '<<step<<endl;
break;
}
s1="";
s2="";
for(int i=0;i<len;i++){
s1+=tmp[i];
}
for(int i=len;i<2*len;i++){
s2+=tmp[i];
}
}
}
return 0;
}
Pots
倒水问题+记录路径
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <string>
#include <queue>
const int N=100+10;
using namespace std;
string str[6]={"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};
struct node{
int a,b;
string s;
};
void print(string st){
cout<<st.length()<<endl;
for(int i=0;i<st.length();i++){
cout<<str[st[i]-'0']<<endl;
}
}
int A,B,C;
int vis[N][N];
int main(){
cin>>A>>B>>C;
queue<node> Q;
Q.push((node){0,0});
vis[0][0]=1;
while(!Q.empty()){
node t=Q.front();Q.pop();
for(int i=0;i<6;i++){
node tmp=t;
//cout<<tmp.a<<' '<<tmp.b<<endl;
if (i==0){
tmp.a=A;
tmp.s+='0';
}
else if (i==1){
tmp.b=B;
tmp.s+='1';
}
else if (i==2){
tmp.a=0;
tmp.s+='2';
}
else if (i==3){
tmp.b=0;
tmp.s+='3';
}
else if (i==4){
if (tmp.a+tmp.b<=B){
tmp.b+=tmp.a;
tmp.a=0;
}
else {
tmp.a=tmp.a-(B-tmp.b);
tmp.b=B;
}
tmp.s+='4';
}
else if (i==5){
if (tmp.b+tmp.a<=A){
tmp.a+=tmp.b;
tmp.b=0;
}
else {
tmp.b=tmp.b-(A-tmp.a);
tmp.a=A;
}
tmp.s+='5';
}
//cout<<tmp.a<<' '<<tmp.b<<endl<<endl;
if (vis[tmp.a][tmp.b]) continue;
if (tmp.a==C||tmp.b==C){
print(tmp.s);
return 0;
}
Q.push(tmp);
vis[tmp.a][tmp.b]=1;
}
}
cout<<"impossible"<<endl;
return 0;
}
Fire Game
用cnt记录草数,可判断是否全部稍晚,还有一个小技巧是,一开始队列入两个着火点
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
const int N=10+10;
const int INF=0x3f3f3f3f;
using namespace std;
struct node{
int x,y;
};
int dx[4]={0,0,-1,1},
dy[4]={-1,1,0,0};
int t,n,m,ans,kase,cnt,now,X,Y,tmp;
int T[N][N],a[N][N];
char ch;
void bfs(int A,int b,int c,int d){
//cout<<A<<b<<c<<d<<endl;
now=2;
if (A==c&&b==d) now--;
tmp=0;
memset(T,-1,sizeof(T));
queue<node> Q;
Q.push((node){A,b});T[A][b]=0;
Q.push((node){c,d});T[c][d]=0;
while(!Q.empty()){
node t=Q.front();Q.pop();
for(int i=0;i<4;i++){
X=t.x+dx[i];
Y=t.y+dy[i];
if (X<0||X>=n||Y<0||Y>=m) continue;
if (!a[X][Y]) continue;
if (T[X][Y]!=-1) continue;
now++;
Q.push((node){X,Y});
T[X][Y]=T[t.x][t.y]+1;
tmp=max(T[X][Y],tmp);
}
}
if (now==cnt) ans=min(tmp,ans);
}
int main(){
cin>>t;
while(t--){
cin>>n>>m;
ans=INF;
kase++;
cnt=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>ch;
if (ch=='.') a[i][j]=0;
else {
cnt++;
a[i][j]=1;
}
}
}
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
for(int k=0;k<n;k++)
for(int L=0;L<m;L++)
if (a[i][j]&&a[k][L]){
bfs(i,j,k,L);
}
/*for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cout<<T[i][j]<<' ';
}
cout<<endl;
}*/
if (ans==INF) ans=-1;
cout<<"Case "<<kase<<": "<<ans<<endl;
}
return 0;
}
Fire!
坑点在着火点可能不止一个
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
const int N=1000+10;
using namespace std;
struct node{
int x,y;
};
int dx[4]={0,0,-1,1},
dy[4]={-1,1,0,0};
char tmp;
int t,n,m,x1,y1,x2,y2,flag,X,Y;
int a[N][N],vis[N][N],D[N][N],T[N][N];
void bfs(int x,int y){
queue<node> Q;
memset(vis,0,sizeof(vis));
node first={x,y};
Q.push(first);
vis[x][y]=1;
while(!Q.empty()){
node t=Q.front();Q.pop();
for(int i=0;i<4;i++){
X=t.x+dx[i];
Y=t.y+dy[i];
if (X<0||X>=n||Y<0||Y>=m) {
if (flag==0){
cout<<D[t.x][t.y]+1<<endl;
return;
}
else continue;
}
if (vis[X][Y]) continue;
if (a[X][Y]) continue;
if (flag) {
if (T[t.x][t.y]+1>=T[X][Y]) continue;
T[X][Y]=T[t.x][t.y]+1;
}
else {
if (D[t.x][t.y]+1>=T[X][Y]) continue;
D[X][Y]=D[t.x][t.y]+1;
}
node t1={X,Y};
Q.push(t1);
vis[X][Y]=1;
}
}
if (flag==0) cout<<"IMPOSSIBLE"<<endl;
}
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
cin>>t;
while(t--){
memset(a,0,sizeof(a));
memset(T,0x3f,sizeof(T));
memset(D,0,sizeof(D));
cin>>n>>m;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>tmp;
if (tmp=='J'){
x2=i;
y2=j;
}
else if (tmp=='F'){
T[i][j]=0;
}
else if(tmp=='#'){
a[i][j]=1;
}
}
}
flag=1;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if (T[i][j]==0) bfs(i,j);
}
}
flag=0;
bfs(x2,y2);
/*for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cout<<T[i][j]<<' ';
}
cout<<endl;
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cout<<D[i][j]<<' ';
}
cout<<endl;
}*/
}
return 0;
}
/*
2
4 4
####
#JF#
#..#
#..#
3 3
###
#J.
#.F
*/
迷宫问题
如何记录路径,这是个问题,可以开两个二维数组记录上一个位置在那里,或者用开一个结构体数组保存,或者用string记录
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
#include <queue>
const int N=5+5;
using namespace std;
struct node{
int x,y,step;
};
int dx[4]={0,0,-1,1},
dy[4]={-1,1,0,0};
int code,Nx,Ny,Ns;
int a[N][N],Lx[N][N],Ly[N][N];
set<int> S;
queue<node> Q;
void print(int x,int y){
if(x==-1&&y==-1) return;
print(Lx[x][y],Ly[x][y]);
printf("(%d, %d)\n",x,y);
}
int main(){
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
cin>>a[i][j];
}
}
code=0;
S.insert(code);
node first={0,0,0};
Q.push(first);
Lx[0][0]=-1;
Ly[0][0]=-1;
while(!Q.empty()){
node tmp=Q.front();Q.pop();
for(int i=0;i<4;i++){
Nx=tmp.x+dx[i];
Ny=tmp.y+dy[i];
Ns=tmp.step+1;
if (Nx<0||Nx>=5||Ny<0||Ny>=5||a[Nx][Ny]) continue;
code=10*Nx+Ny;
if(S.find(code)==S.end()){
node t={Nx,Ny,Ns};
Lx[Nx][Ny]=tmp.x;
Ly[Nx][Ny]=tmp.y;
Q.push(t);
S.insert(code);
}
if(Nx==4&&Ny==4){
print(4,4);
return 0;
}
}
}
return 0;
}
Oil Deposits
联通块问题
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
const int N=100+10;
using namespace std;
char tmp;
int n,m,cnt;
int a[N][N],vis[N][N];
int dx[8]={-1,-1,-1, 0, 0, 1, 1, 1},
dy[8]={-1, 0, 1,-1, 1,-1, 0, 1};
void dfs(int x,int y){
int x1,y1;
vis[x][y]=1;
for(int i=0;i<8;i++){
x1=x+dx[i];
y1=y+dy[i];
if (a[x1][y1]&&!vis[x1][y1]&&x1>=0&&x1<n&&y1>=0&&y1<m) dfs(x1,y1);
}
}
int main(){
while(1){
cin>>n>>m;
if (!n&&!m) break;
cnt=0;
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>tmp;
if (tmp=='@') a[i][j]=1;
else a[i][j]=0;
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if (a[i][j]&&!vis[i][j]) {
cnt++;
dfs(i,j);
}
}
}
cout<<cnt<<endl;
}
return 0;
}
非常可乐
倒水问题,很明显S需要是偶数,这里可以稍微剪一下枝
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
const int N=100+10;
using namespace std;
struct node{
int v[3],step;
};
int m[3],t1[3],s,vis[N][N][N];
int ok(int a,int b,int c){
if (a==b&&c==0) return 1;
if (a==c&&b==0) return 1;
if (b==c&&a==0) return 1;
return 0;
}
void bfs(){
memset(vis,0,sizeof(vis));
queue<node> Q;
node first={0,0,m[2],0};
Q.push(first);
vis[0][0][m[2]]=1;
while(!Q.empty()){
node t=Q.front();Q.pop();
s=t.step+1;
for(int i=0;i<3;i++){
if (!t.v[i]) continue;
for(int j=0;j<3;j++){
if (i!=j&&t.v[j]<m[j]){
for(int i=0;i<3;i++) t1[i]=t.v[i];
if (t.v[i]+t.v[j]<=m[j]){
t1[j]=t1[i]+t1[j];
t1[i]=0;
}
else{
t1[i]=t1[i]-(m[j]-t1[j]);
t1[j]=m[j];
}
if (vis[t1[0]][t1[1]][t1[2]]) continue;
if (ok(t1[0],t1[1],t1[2])) {
cout<<s<<endl;
return;
}
node T={t1[0],t1[1],t1[2],s};
Q.push(T);
vis[t1[0]][t1[1]][t1[2]]=1;
}
}
}
}
cout<<"NO"<<endl;
}
int main(){
while(1){
scanf("%d%d%d",&m[2],&m[0],&m[1]);
if (!m[0]&&!m[1]&&!m[2]) break;
if (m[2]%2){
cout<<"NO"<<endl;
continue;
}
bfs();
}
return 0;
}
Find a way
要注意有些KFC是不能到达的
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
const int N=200+10;
using namespace std;
char tmp;
int n,m,k,code,x1,y1,x2,y2,X,Y,ans,flag,cnt;
int a[N][N],D[N][N],D1[N][N];
int dx[4]={-1,1,0,0},
dy[4]={0,0,-1,1};
struct node{
int x,y;
};
queue<node> Q;
set<int> S;
void bfs(){
while(!Q.empty()&&k<cnt){
node t=Q.front();Q.pop();
for(int i=0;i<4;i++){
X=t.x+dx[i];
Y=t.y+dy[i];
if (X<0||X>=n||Y<0||Y>=m||a[X][Y]==1) continue;
code=1000*X+Y;
if (S.find(code)==S.end()){
node t1={X,Y};
Q.push(t1);
S.insert(code);
if (flag==0) D[X][Y]=D[t.x][t.y]+1;
else D1[X][Y]=D1[t.x][t.y]+1;
if (a[X][Y]==2) k++;
}
}
}
}
int main(){
while(cin>>n>>m){
cnt=0;
memset(a,0,sizeof(a));
memset(D,0,sizeof(D));
memset(D1,0,sizeof(D1));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>tmp;
if (tmp=='Y') {
x1=i;
y1=j;
}
else if (tmp=='M'){
x2=i;
y2=j;
}
else if (tmp=='@'){
a[i][j]=2;
cnt++;
}
else if (tmp=='#'){
a[i][j]=1;
}
}
}
while (!Q.empty()) Q.pop();
S.clear();
node first={x1,y1};
Q.push(first);
S.insert(1000*x1+y1);
k=0;
flag=0;
bfs();
/*for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cout<<D[i][j]<<' ';
}
cout<<endl;
}*/
while (!Q.empty()) Q.pop();
S.clear();
node first1={x2,y2};
Q.push(first1);
S.insert(1000*x2+y2);
k=0;
flag=1;
bfs();
/*for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cout<<D1[i][j]<<' ';
}
cout<<endl;
}*/
ans=0x3f3f3f3f;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if (a[i][j]==2&&D[i][j]&&D1[i][j]) ans=min(ans,D[i][j]+D1[i][j]);
}
}
cout<<ans*11<<endl;
}
return 0;
}