搜索专题
1.模拟战役
原题链接:https://ac.nowcoder.com/acm/contest/86654/C
算出敌我的联通块数量和自身联通块包含大炮的数量数列,若我方少于敌方联通块,就返回-1,否则贪心地留下含有较多大炮的联通块并累加
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int m,ans;
char a[1000][1000];
int sign[1000][1000];
int t,s[1000000],res;
int dx[8]={-1,-1,-1,0,0,1,1,1},dy[8]={-1,0,1,-1,1,-1,0,1};
void bfs1(int x,int y)
{
sign[x][y]=1;
for(int i=0;i<8;i++)
{
int X=x+dx[i],Y=y+dy[i];
if(X>=1&&X<=4&&Y>=1&&Y<=m&&a[X][Y]=='*'&&!sign[X][Y])
{
bfs1(X,Y);
}
}
return;
}
int bfs2(int x,int y)
{
ans++;
sign[x][y]=1;
for(int i=0;i<8;i++)
{
int X=x+dx[i],Y=y+dy[i];
if(X>=5&&X<=8&&Y>=1&&Y<=m&&a[X][Y]=='*'&&!sign[X][Y])
{
bfs1(X,Y);
}
}
return ans;
}
signed main()
{
cin>>m;
for(int i=1;i<=8;i++)
{
getchar();
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
}
}
for(int i=1;i<=4;i++)
{
for(int j=1;j<=m;j++)
{
if(!sign[i][j]&&a[i][j]=='*')
t++,bfs1(i,j);
}
}
//cout<<t<<endl;
for(int i=5;i<=8;i++)
{
for(int j=1;j<=m;j++)
{
if(!sign[i][j]&&a[i][j]=='*')
{
s[res++]=bfs2(i,j);
}
}
}
if(res<t)
{
cout<<-1<<endl;
return 0;
}
sort(s,s+res);
int sum=0;
for(int i=t+1;i<res;i++)
sum+=s[i];
cout<<sum<<endl;
return 0;
}
2.Jelly
原题链接:https://ac.nowcoder.com/acm/contest/86654/D
三维bfs板板,但是注意起始加一
查看代码
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=110;
char g[N][N][N];
int f[N][N][N];
typedef struct go
{
int yi;
int er;
int san;
}PII;
int n,m;
void bfs()
{
queue<PII> q;
q.push({1,1,1});
memset(f,-1,sizeof f);
f[1][1][1]=1;
while(!q.empty())
{
PII start = q.front();
q.pop();
g[start.yi][start.er][start.san]='*';
int dx[6]={0,0,0,0,-1,1},dy[6]={0,0,-1,1,0,0},dz[6]={1,-1,0,0,0,0};
for(int i=0;i<6;i++)
{
int x=start.yi+dx[i],y=start.er+dy[i],z=start.san+dz[i];
if(g[x][y][z]=='.')
{
g[x][y][z]='*';
f[x][y][z]=f[start.yi][start.er][start.san]+1;
q.push({x,y,z});
}
}
}
cout<<f[n][n][n];
}
int main()
{
memset(g,'*',sizeof(g));
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
cin>>g[i][j][k];
bfs();
return 0;
}
3.寻找道路
原题链接:https://ac.nowcoder.com/acm/contest/86654/E
要使路径所有点指向终点,那就从终点倒着遍历,能遍历到就打标,并且将连通着没打上标的点的点去标记,最后正着遍历即可
查看代码
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=200010;
vector<int> v1[N],v2[N];
typedef pair <int ,int>PII;
int n,m,s,t;
int sign[N],vis[N],vis2[N];
void dfs(int x)
{
sign[x]=1;
for(int i=0;i<v2[x].size();i++)
{
if(!sign[v2[x][i]])
{
dfs(v2[x][i]);
}
}
}
void bfs()
{
queue<PII>q;
q.push({s,0});
vis[s]=1;
while(!q.empty())
{
PII f=q.front();
q.pop();
if(f.first==t)
{
cout<<f.second<<endl;
return;
}
for(int i=0;i<v1[f.first].size();i++)
{
if(!vis[v1[f.first][i]]&&vis2[v1[f.first][i]])
{
vis[v1[f.first][i]]=1;
q.push({v1[f.first][i],f.second+1});
}
}
}
cout<<-1;
return;
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
int x,y;
cin>>x>>y;
v1[x].push_back(y);
v2[y].push_back(x);
}
cin>>s>>t;
dfs(t);
for(int i=1;i<=n;i++)
{
vis2[i]=1;
for(int j=0;j<v1[i].size();j++)//路径上的所有点的出边所指向的点都直接或间接与终点连通
{
if(!sign[v1[i][j]])
{
vis2[i]=0;
}
}
}
bfs();
return 0;
}
4.送外卖
原题链接:https://ac.nowcoder.com/acm/contest/86654/F
和上一题有异曲同工之妙,但是这个要先建图建边再从后往前遍历打标,再次正向遍历,注意优先走a即可
查看代码
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=200010;
vector<int> v1[N],v2[N];
typedef pair <int ,int>PII;
int n,m,s,t;
bool f;
char ans[N];
int a[N],b[N];
int sign[N],vis[N],vis2[N];
void dfs(int x)//从后往前遍历打标
{
sign[x]=1;
for(int i=0;i<v1[x].size();i++)
{
if(!sign[v1[x][i]])
{
dfs(v1[x][i]);
}
}
}
void dfs2(int x,int step)
{
if(x<0||x>=n)return;
if(step>=n)return;//防死循环
if(x==n-1)
{
f=true;
return;
}
if(x+a[x]>=0&&x+a[x]<n&&sign[x+a[x]])
{
ans[step]='a';
dfs2(x+a[x],step+1);
}
else
{
ans[step]='b';
dfs2(x+b[x],step+1);
}
}
int main()
{
cin>>n;
//所在小区i加上ai或bi是直接到达的地方
for(int i=0;i<n;i++)
{
cin>>a[i];
if(i+a[i]>=0&&i+a[i]<n)
v1[i+a[i]].push_back(i);//建图建边
}
for(int i=0;i<n;i++)
{
cin>>b[i];
if(i+b[i]>=0&&i+b[i]<n)
v1[i+b[i]].push_back(i);
}
dfs(n-1);
if(!sign[0])
{
cout<<"No solution!";
return 0;
}
dfs2(0,0);
if(f)
{
cout<<ans;
}
else
{
cout<<"Infinity!";
}
return 0;
}
5.数独挑战
原题链接:https://ac.nowcoder.com/acm/contest/86654/G
运用位运算,将每行每列每个区块变成二进制串,例如某一行有4,9这两个数,那么这一行的二进制串就是100001000,利用这个进行搜索,每次搜索锁定的某个空,遍历九个数字运用&运算判断行列块是否可以填这个数
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[10][10];
int h[1000],l[1000],k[1000];
int ans,ok;
void dfs(int x,int y,int z) {
if(ok)return;
if(z>ans)
{
ok=1;
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
cout<<a[i][j]<<" ";
}
cout<<endl;
}
return;
}
while (a[x][y])
{
y++;
if (y > 9)x++, y = 1;
}
for (int i = 1; i <= 9; i++)
{
if(h[x]&(1<<i)||l[y]&(1<<i)||k[((x-1)/3)*3+(y+2)/3]&(1<<i))
{
continue;
}
a[x][y]=i;
h[x]|=(1<<i),l[y]|=(1<<i),k[((x-1)/3)*3+(y+2)/3]|=(1<<i);
dfs(x,y,z+1);
a[x][y]=0;
h[x]^=(1<<i),l[y]^=(1<<i),k[((x-1)/3)*3+(y+2)/3]^=(1<<i);
}
}
signed main()
{
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
cin>>a[i][j];
if(a[i][j]==0)ans++;
h[i]|=(1<<a[i][j]);
l[j]|=(1<<a[i][j]);
k[((i-1)/3)*3+(j+2)/3]|=(1<<a[i][j]);
}
}
dfs(1,1,1);
return 0;
}
6.单词接龙
原题链接:https://ac.nowcoder.com/acm/contest/86654/N
建图建边遍历即可
查看代码
#include<bits/stdc++.h>
using namespace std;
int a[100];
int ans;
int sign[1000000];
struct node{
int x;//增长
int num;//编号
node(int x,int num):x(x),num(num){}
};
vector<vector<node>> g(30);
int n,ma;
string c="";
vector<string> s(1000000);
void dfs(int deep,int num)
{
ma=max(ma,deep);
for(int i=0;i<g[num].size();i++)
{
if(sign[g[num][i].num]<2) {
sign[g[num][i].num]++;
dfs(deep+g[num][i].x,g[num][i].num);
sign[g[num][i].num]--;
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>s[i];
}
char p;
cin>>p;
for(int i=1;i<=n;i++)//建边,能连起来就搞一条边,并记录能多出来的长度
{
if(s[i][0]==p)g[0].push_back(node(s[i].size(),i));//开头是p的记录进去,从他们开始遍历
for(int j=1;j<=n;j++)
{
int t=min(s[i].size(),s[j].size());
for(int k=1;k<=t;k++)
{
if(s[i].substr(s[i].size()-k)==s[j].substr(0,k))
{
g[i].push_back(node(s[j].size()-k,j));
}
}
}
}
dfs(0,0);
cout<<ma;
return 0;
}