天天快乐编程集训队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 棋盘

模拟过程中的状态即可

posted @ 2021-08-12 08:33  暴力都不会的蒟蒻  阅读(82)  评论(0编辑  收藏  举报