天天快乐编程集训队2021暑假训练-0812-搜索题解
1.4833 选数
数据量不大,利用深搜枚举k个即可。还需要写一个Prime判断素数函数
#include<bits/stdc++.h>
using namespace std;
int n,k;
int a[20];
int ans;
int Prime(int n)
{
if(n<2)return 0;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
return 0;
}
}
return 1;
}
//dfs(当前下标,选的个数,已经选的总和)
void dfs(int cur,int tot,int sum)
{
if(tot==k)
{
if(Prime(sum))ans++;
return;
}
if(cur>=n)return;
dfs(cur+1,tot+1,sum+a[cur]);
dfs(cur+1,tot,sum);
}
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++)cin>>a[i];
dfs(0,0,0);
cout<<ans;
return 0;
2.3533 黑白图像
要搜索八连块的个数,我们可以利用搜索求解,走过标记一下下次不再搜即可。
700*700=490000,TZOJ允许的递归深度小于65536次,所以只能利用BFS广搜
广搜的步骤如下:
1、选择其中一个可以开始的点作为起点开始搜索
2、设置两个变量分别表示当前的点和总共需要访问的点数
3、把起点放进我们定义好的数组里,并标记已经访问过执行循环直到访问完所有的点,执行过程如下:
1)当前点是否为终点,是终点就结束
2)对8个方向数组进行遍历得到下一个要访问的位置,判断每个位置是否越界、访问情况,如果不越界且可以被访问表明这个点可以之后访问,那么把它加在最后一个点后面。
3)进行下一个点
#include <bits/stdc++.h>
using namespace std;
//定义成全局变量,这样可以在任何地方访问
//且vis数组的值全为0,代表还没访问
int n;
int ans;
//定义一个结构体来存储
struct T
{
//结构体需要存储当前的坐标(x,y)
int x, y;
};
//最多有700*700个点可以走
//数组太大,必须全局
T a[700 * 700];
int vis[700][700];
char mat[700][700];
//可以开始的点太多,改成函数,可以传入坐标(x,y)
void bfs(int x, int y)
{
//定义tot代表当前的总个数,cur代表当前进行到哪个了
int tot = 0, cur = 0;
//信奥不支持C++11,要一个一个元素进行赋值
a[tot].x = x;
a[tot++].y = y;
//起始点被访问过了
vis[x][y] = 1;
//直到执行到最后一个
while (cur < tot)
{
//直接输出进行debug也是很快的方法
//cout<<"debug: 这次访问坐标为("<<a[cur].x<<","<<a[cur].y<<")\n";
//不存在终点问题,我们只负责每次标记有没有访问过,一次标记的为一块
//这种八个方向其实为[-1,0,1]的组合,可以直接循环
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
//根绝方向数组得到下一个位置
int tx = a[cur].x + i;
int ty = a[cur].y + j;
//越界的不考虑
if (tx < 0 || ty < 0 || tx >= n || ty >= n)
continue;
//访问过的或者是0的不能访问
if (vis[tx][ty] || mat[tx][ty] == '0')
continue;
//满足把当前点放进去
a[tot].x = tx;
a[tot++].y = ty;
//加过之后当前点就被访问过了
vis[tx][ty] = 1;
}
}
//这个点访问过了,访问下一个
cur++;
}
}
int main()
{
cin >> n;
//读取n行字符串
for (int i = 0; i < n; i++)
cin >> mat[i];
ans = 0;
//循环访问二维矩阵每一个点
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
//是黑色的,而且没有被访问过
if (mat[i][j] == '1' && vis[i][j] == 0)
{
bfs(i, j);
//八连块+1
ans++;
}
}
}
cout << ans << "\n";
return 0;
}
我们昨天学习了STL queue,当然本题也可以用它
#include <bits/stdc++.h>
using namespace std;
char a[701][701];
int n;
struct Node
{
int x,y;
}s,e;
int visited[701][701];
int dir[8][2]={-1,0,1,0,0,1,0,-1,1,1,-1,-1,1,-1,-1,1};
bool Check(int x,int y)
{
return x>=0&&x<n&&y>=0&&y<n&&a[x][y]!='0';
}
int BFS()
{
queue<Node> qu;
qu.push(s);
visited[s.x][s.y]=1;
while(!qu.empty())
{
Node cur=qu.front();
qu.pop();
Node nxt;
for(int i=0;i<8;i++)
{
nxt.x=cur.x+dir[i][0];
nxt.y=cur.y+dir[i][1];
if(Check(nxt.x,nxt.y)&&visited[nxt.x][nxt.y]==0)
{
visited[nxt.x][nxt.y]=1;
qu.push(nxt);
}
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cin>>a[i][j];
}
}
int num=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(a[i][j]=='1'&&visited[i][j]==0)
{
s.x=i;
s.y=j;
BFS();
num++;
}
}
}
cout<<num<<endl;
return 0;
}
震惊,现在TZOJ不卡栈了,深搜也可以AC了
#include <bits/stdc++.h>
using namespace std;
int n,vis[750][750],ans;
string s[750];
int d[8][2]={1,0,0,1,-1,0,0,-1,1,1,1,-1,-1,1,-1,-1};
void dfs(int x,int y)
{
if(x<0||x>=n||y<0||y>=n||vis[x][y]||s[x][y]=='0') return;
vis[x][y]=1;
for(int i=0;i<8;i++)
{
int tx=x+d[i][0],ty=y+d[i][1];
dfs(tx,ty);
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>s[i];
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(s[i][j]=='1'&&!vis[i][j])
{
ans++;
dfs(i,j);
}
}
}
cout<<ans<<"\n";
return 0;
}
3.4842 火星人
给定一个序列,输出这个序列在全排列集合中后面的第m个序列
#include<bits/stdc++.h>
using namespace std;
int a[10005],vis[10005];
int n,m;
//tot=0,表示推进初始状态
int tot=0,flag=0;
//dfs(第x个状态)
void dfs(int x)
{
if(flag)return;
if(x>n)//已经过了初始状态
{
tot++;//往 m 出发,计数
if(tot>m)//找到了
{
printf("%d",a[1]);
for(int i=2;i<=n;i++) printf(" %d",a[i]);
flag=1;
}
}
//全排列
for(int i=1;i<=n;i++)
{
//初始状态,值是定的
if(tot==0) i=a[x];
//过了初始状态,i值才动
if(vis[i]==0)
{
//填上i
a[x]=i;
vis[i]=1;
dfs(x+1);
vis[i]=0;
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
dfs(1);
return 0;
}
找到位置进行模拟
#include<bits/stdc++.h>
using namespace std;
int n,k,a[10005];
bool vis[10005];
int main()
{
cin>>n>>k;
for(int i=1,u;i<=n;i++)
{
cin>>u;
int x=u;
for(int j=1;j<=u;j++) x-=vis[j];
vis[u]=1,a[i]=x-1;
}
a[n]+=k;
for(int i=n;i>0;i--)
{
a[i-1]+=a[i]/(n-i+1);
a[i]%=(n-i+1);
}
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
for(int j=0;j<=a[i];j++) if(vis[j]) a[i]++;
if(i!=1) cout<<" ";
cout<<a[i]+1;
vis[a[i]]=1;
}
return 0;
}
STL中的next_permutation直接秒杀
#include<bits/stdc++.h>
using namespace std;
int n,k,a[10010];
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++)cin>>a[i];
while(k--)next_permutation(a,a+n);
cout<<a[0];
for(int i=1;i<n;i++)cout<<" "<<a[i];
return 0;
}
4.5995 奶酪
并查集、深搜、广搜均可
5.6285 2的幂次方表示
用进制转换进行递归
#include<bits/stdc++.h>
using namespace std;
void dfs(int m, int n)
{
if (m == 0)return;
//进制转换
int r = m % 2;
m /= 2;
//继续递归
dfs(m, n + 1);
if(m&&r)cout<<"+";
if (r == 1)
{
//0 1 2特别输出
if (n == 0)
cout << "2(0)";
else if (n == 1)
cout << "2";
else if (n == 2)
cout << "2(2)";
else
{
//其他继续处理
cout<<"2(";
dfs(n,0);
cout<<")";
}
}
}
int main()
{
int n;
cin>>n;
dfs(n,0);
return 0;
}
6.5993 棋盘
模拟过程中的状态即可
本文来自博客园,作者:暴力都不会的蒟蒻,转载请注明原文链接:https://www.cnblogs.com/BobHuang/p/15131054.html