FZU ACM 寒假第五讲:搜索算法

第一题:自然数的拆分问题

source:

洛谷 - P2404

解题思路:经典的深搜,只是要注意一下结束条件和递归的逻辑顺序;

以及保证每行输出的单调

ACcode:

#include 
using namespace std;
int n;
int a[10];
void dfs(int step,int sum,int beg )
{
	if(sum>n)
	{
		return ;
	}
	if(sum==n)
	{
		cout<>n;
	dfs(0,0,1);
	return 0;
} 

第二题:填涂颜色

source:洛谷 - P1162

解题思路:依旧是DFS,代码中有详细注释;

ACcdoe:

#include 
using namespace std;

int n;
int dtx[4] = {1, -1, 0, 0};
int dty[4] = {0, 0, 1, -1};
int a[35][35] = {0};
int pin[35][35] = {0};  // 拷贝一份原数组 

void dfs(int a[][35], int cur_x, int cur_y) {
    // 判断当前位置是否越界或者当前位置已经是 1(表示已访问或者本身就是墙)
    if (cur_x < 0 || cur_x > n + 1 || cur_y < 0 || cur_y > n + 1 || a[cur_x][cur_y] == 1)
        return;

    // 将当前位置标记为已访问(标记为 1)
    a[cur_x][cur_y] = 1;

    // 遍历四个方向进行递归搜索
    for (int i = 0; i < 4; i++) {
        int new_x = cur_x + dtx[i];
        int new_y = cur_y + dty[i];
        dfs(a, new_x, new_y);
    }
}

int main() {
    cin >> n;
    // 从 1 开始读入矩阵元素,给最外边加一圈 0,方便找到入口涂色
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> a[i][j];
            pin[i][j] = a[i][j];
        }
    }
    // 开始从 (0, 0) 位置进行深度优先搜索,标记所有与边界相连的 0
    dfs(a, 0, 0);

    // 遍历矩阵内部(不包括最外层)
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            // 如果某个位置仍然是 0,说明它被 1 包围,将其标记为 2
            if (a[i][j] == 0)
                cout << 2 << " ";
            else
                cout << pin[i][j] << " ";
        }
        cout << endl;
    }

    return 0;
}

第三题:显示图像

source:

洛谷 - P1256

解题思路:一般首先想到的是从每一个0出发最近的1,但是这样不可避免的出现重复寻访;我们可以找到每一个1作为起点去搜索每个0与之的距离,这里我们利用的是BFS;而不同1与同一个零的距离可能不同,于是在搜索中不断更新每个位置的最短距离;

ACcode:

#include 
using namespace std;
int n,m;
int dis[210][210];//存0到达1最短距离
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};//向上下左右移动
char sn[210][210];//存01矩阵 因为数字间无空格所以用字符数组存储
void bfs(int x,int y){
    queue > q;
    q.push({x,y});//入队
    while(q.size()){
        pair now=q.front();//取队头
        q.pop();//出队
        int a=now.first,b=now.second;
        for(int i = 0;i<=3;i++){//向四个方向移动
            int xx=a+dx[i],yy=b+dy[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&sn[xx][yy]=='0'&&dis[xx][yy]>dis[a][b]+1){
                //判断是否越界 是否能走 是否得更短距离
                dis[xx][yy]=dis[a][b]+1;//距离+1
                q.push({xx,yy});//入队
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1;i<=n;i++)
        for(int j = 1;j<=m;j++)
            cin >> sn[i][j];
    for(int i = 1;i<=n;i++)
        for(int j = 1;j<=m;j++)
            dis[i][j]=1e6;//初始化 因为是求最小值,如果不初始化数值不会改变
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++){
            if(sn[i][j]=='1'){
                dis[i][j]=0;
                bfs(i,j);
            }
        }
    }
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++){
            if(sn[i][j]=='1') printf("0 ");//如果是‘1’那么本身就是白色色块
            else cout << dis[i][j]<<" ";
        }
        cout << "\n";
    }
    return 0;
}

 第四题:健康的荷斯坦奶牛 Healthy Holsteins

source:

洛谷 - P1460 

 解题思路:对于每一种饲料,要么需要这种饲料,要么不需要,显然是一题DFS的题目,check函数判断是否还需要往下搜索。

ACcode:

#include
using namespace std;
int n,m,a[1001],p[1001],b[1001],c[1001][1001];
bool check(int a[],int n){//判断
	for(int i=1;i<=m;i++){
		int s=0;
		for(int j=1;j<=n;j++)
		    s+=c[a[j]][i];
		if(s>m;//牛
	for(int i=1;i<=m;i++)cin>>b[i];
	cin>>n;//饲料
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=m;j++)cin>>c[i][j];
	for(int i=1;i<=n;i++){
	    js(1,n,i);
	}
}

第五题:GRZ-Ridges and Valleys

source:

洛谷 - P3456

 解题思路:这题依旧是BFS,注意这题需要判断每一个格子周围的八个方位的高度情况,具体的在题中有详细注释;

ACcode:

#include
using namespace std;
#define int long long//不良习惯( 
 
int n,a[1050][1050],vis[1050][1050];//a是输入的,vis是标记是否搜过以及第几轮搜过
int flag1,flag2,cnt1,cnt2,uwu;//flag在bfs时候使用,cnt2山峰数量,cnt1山谷数量,uwu广搜判断标记时用 
int fx[8]={0,0,1,-1,1,1,-1,-1};
int fy[8]={1,-1,0,0,-1,1,-1,1};//方向数组 
struct qwq
{
	int x,y;
}tool1,tool2;//结构体存点,之后bfs有用 
void bfs(int x,int y,int k)//x,y是坐标,k是当前连通块内的值 
{
	queueq;//队列 
	tool1.x=x;
	tool1.y=y;
	q.push(tool1);//bfs到的初始点入队 
	while(!q.empty())//平平无奇的bfs 
	{
		tool2=q.front();//取出队首 
		q.pop();//出队(不出会死循环) 
		int tx=tool2.x;
		int ty=tool2.y;
		for(int i=0;i<8;i++)//各个方向 
		{
			int xx=tx+fx[i];
			int yy=ty+fy[i];
			if(xx<=0||yy<=0||xx>n||yy>n)	continue;//边界 
			if(vis[xx][yy]==uwu)	continue;//防死循环(本次循环已搜过了) 
			if(a[xx][yy]==k)//值相等,即为在同一个块里 
			{
				vis[xx][yy]=uwu;
				tool1.x=xx;
				tool1.y=yy;
				q.push(tool1);//入队,搜索 
				continue;
			}
			if(a[xx][yy]>k)	flag1=1;//有比它高的
			if(a[xx][yy]>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j];
		}
	}//输入 
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(vis[i][j])	continue;//搜过就不搜了 
			vis[i][j]=++uwu;
			flag1=0;
			flag2=0;//flag清零 
			bfs(i,j,a[i][j]);//广搜 
		}
	}
	cout<

第六题:八皇后 Checker Challenge

source:

洛谷 - P1219 

解题思路:经典深搜问题,需要记录行、列、主、副对角线是否已经存在皇后,从而进行深层次递归;

ACcode:

#include
#include
#include
#include
#include
#include
using namespace std;
int a,ans[14],acount=0;
int book[14],djg=0;
bool check(int n,int index){  //表示放第 n 个皇后,在第 i 个位置可不可以
	for(int i=1;i>a;
	dfs(1);
	cout<

你可能感兴趣的:(算法)