• 天天快乐编程集训队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<<")
    ";
            //不存在终点问题,我们只负责每次标记有没有访问过,一次标记的为一块
            //这种八个方向其实为[-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 << "
    ";
        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<<"
    ";
    	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 棋盘

    模拟过程中的状态即可

    大佬您太强了,还请多多指教哎
  • 相关阅读:
    空中楼阁 ( House )最短路
    [hdu4333]Revolving Digits
    vue element-ui el-table 选择框单选修改
    css 中间文字 两边横线
    uni-app计算scroll-view高度
    Swift Playgrounds Mac 编程学习入门
    vuecli vue.config.js 通用配置
    vuecli3 分环境打包的方案
    mysql 插入更新
    关闭进程
  • 原文地址:https://www.cnblogs.com/BobHuang/p/15131054.html
Copyright © 2020-2023  润新知