学习日记12/29,好日子呀好日子

这篇博客介绍了如何使用深度优先搜索(DFS)解决两个信息技术问题:一是填充数字矩阵中的闭合圈,二是寻找田地中水坑的数量。作者提供了详细的代码实现,并强调了搜索过程中需要注意的细节,如边界条件和回溯操作。此外,还讨论了一种处理多个题目时间最短的DFS解决方案。
摘要由CSDN通过智能技术生成

今天没有别的东西全是dfs,刚学嘛多搞点练一下呗

题目描述

由数字 00 组成的方阵中,有一任意形状闭合圈,闭合圈由数字 11 构成,围圈时只走上下左右 44 个方向。现要求把闭合圈内的所有空间都填写成 22。例如:6\times 66×6 的方阵(n=6n=6),涂色前和涂色后的方阵如下:

0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1

输入格式

每组测试数据第一行一个整数 n(1 \le n \le 30)n(1≤n≤30)。

接下来 nn 行,由 00 和 11 组成的 n \times nn×n 的方阵。

方阵内只有一个闭合圈,圈内至少有一个 00。

//感谢黄小U饮品指出本题数据和数据格式不一样. 已修改(输入格式)

输出格式

已经填好数字 22 的完整方阵。

输入输出样例

输入 #1复制

6
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1

输出 #1复制

0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1

说明/提示 

对于 100\%100% 的数据,1 \le n \le 30 1≤n≤30。

这题目打了搜索的标签那就用搜索来搞 ,n最大才30.不怕的啦。

思路就是把外围的0给它找到然后用另一张专门的标记地图来标记,最后再染色在原地图的上为0且未被标记的就是被围住的0把他们变成2,然后输出就可以了。(这思路绝对够易懂)

上码。

#include<stdio.h>
int a[33][33]={0};
int b[33][33]={0};
int bx[4]={0,0,1,-1};
int by[4]={1,-1,0,0};
int n;//没错这又是方向键上下左右baba
void ji(int v){
for(int p=1;p<=v;p++){
    for(int y=1;y<=v;y++)
        printf("%d ",b[p][y]);
    printf("\n");
}
}
void f(int x,int c){
if(b[x][c]==1||x<0||c>n+1||x>n+1||c<0){
    return;
}
else{
    a[x][c]=1;
   for(int y=0;y<4;y++){
       if(b[x+bx[y]][c+by[y]]==0&&a[x+bx[y]][c+by[y]]==0){//标记了就没必要再标记了
         f(x+bx[y],c+by[y]);
         //没有要还原的。
       }

}
}
}
void F(int n){//涂颜色的环节

for(int h=1;h<=n;h++){
   for(int j=1;j<=n;j++){
    if(b[h][j]==0&&a[h][j]==0)//没有被a数组标记的0那就是被围住的。
        b[h][j]=2;
   }
}
   ji(n);
}

int main(){
    scanf("%d",&n);
for(int m=1;m<=n;m++){
    for(int u=1;u<=n;u++){
        scanf("%d",&b[m][u]);
    }
}
f(0,0);//从0,0开始你也可以从其它的最外圈的一个点开始,都可以的啦。

F(n);

return 0;
}

不过有些要注意的了,外围的0可能没连在一起 ,那就搜了个寂寞,我刚开始就错了,所以我们就给它多加一圈,这就是n+1的含义。

再来再来

由于近期的降雨,雨水汇集在农民约翰的田地不同的地方。我们用一个 N\times M(1\leq N\leq 100, 1\leq M\leq 100)N×M(1≤N≤100,1≤M≤100) 的网格图表示。每个网格中有水(W) 或是旱地(.)。一个网格与其周围的八个网格相连,而一组相连的网格视为一个水坑。约翰想弄清楚他的田地已经形成了多少水坑。给出约翰田地的示意图,确定当中有多少水坑。

输入第 11 行:两个空格隔开的整数:NN 和 MM。

第 22 行到第 N+1N+1 行:每行 MM 个字符,每个字符是 W 或 .,它们表示网格图中的一排。字符之间没有空格。

输出一行,表示水坑的数量。

输入输出样例

输入 #1复制

10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.

输出 #1复制

3

说明/提示

OUTPUT DETAILS: There are three ponds: one in the upper left, one in the lower left, and one along the right side.

 提示 :从第一个水洼W开始对八个方向进行搜索,采用标记染色的方法,将走过的路径标记上,每全部搜索一次ans+1

这个提示一下就给了思路没啥说的dfs就这莫写就完了,但是这个标记就有点说法了看下面的代码是如何处理的。

#include<stdio.h>
char a[102][102];
 //打标记的数组
int bx[8]= {0,0,1,-1,1,1,-1,-1};
int by[8]= {1,-1,0,0,1,-1,1,-1};
int n,v;//没错这又是方向键不过方像是八个了
int i=0;
void f(int x,int c)
{

        a[x][c]='.';//因为原有的数据不要输出那改了也没关系的就不开标记地图了,可以理解为填坑抓到一个填一个。
        for(int y=0; y<8; y++)
        {
            if((x+bx[y]>=0&&x+bx[y]<n)&&(c+by[y]>=0&&c+by[y]<v))//不要越界。
            {
                if(a[x+bx[y]][c+by[y]]=='W') //标记了就没必要再标记了
                {
                    f(x+bx[y],c+by[y]);//往下找W
                    //没有要还原的。
                }
            }
        }

}

int main()
{
    scanf("%d%d",&n,&v);//
    for(int m=0; m<n; m++)
    {
        scanf("%s",a[m]);
    }
    for(int l=0; l<n; l++)
    {
        for(int y=0; y<v; y++)
        {
            if(a[l][y]=='W') 
            {
                f(l,y);//把这个水坑全给它填了
                i++;
            }
        }
    }
    printf("%d",i);
    return 0;
}

ok下一个。 

 

题目背景

kkksc03 的大学生活非常的颓废,平时根本不学习。但是,临近期末考试,他必须要开始抱佛脚,以求不挂科。

题目描述

这次期末考试,kkksc03 需要考 44 科。因此要开始刷习题集,每科都有一个习题集,分别有 s_1,s_2,s_3,s_4s1​,s2​,s3​,s4​ 道题目,完成每道题目需要一些时间,可能不等(A_1,A_2,\ldots,A_{s_1}A1​,A2​,…,As1​​,B_1,B_2,\ldots,B_{s_2}B1​,B2​,…,Bs2​​,C_1,C_2,\ldots,C_{s_3}C1​,C2​,…,Cs3​​,D_1,D_2,\ldots,D_{s_4}D1​,D2​,…,Ds4​​)。

kkksc03 有一个能力,他的左右两个大脑可以同时计算 22 道不同的题目,但是仅限于同一科。因此,kkksc03 必须一科一科的复习。

由于 kkksc03 还急着去处理洛谷的 bug,因此他希望尽快把事情做完,所以他希望知道能够完成复习的最短时间。

输入格式

本题包含 55 行数据:第 11 行,为四个正整数 s_1,s_2,s_3,s_4s1​,s2​,s3​,s4​。

第 22 行,为 A_1,A_2,\ldots,A_{s_1}A1​,A2​,…,As1​​ 共 s_1s1​ 个数,表示第一科习题集每道题目所消耗的时间。

第 33 行,为 B_1,B_2,\ldots,B_{s_2}B1​,B2​,…,Bs2​​ 共 s_2s2​ 个数。

第 44 行,为 C_1,C_2,\ldots,C_{s_3}C1​,C2​,…,Cs3​​ 共 s_3s3​ 个数。

第 55 行,为 D_1,D_2,\ldots,D_{s_4}D1​,D2​,…,Ds4​​ 共 s_4s4​ 个数,意思均同上。

输出格式

输出一行,为复习完毕最短时间。

输入输出样例

输入 #1复制

1 2 1 3		
5
4 3
6
2 4 3

输出 #1复制

20

说明/提示

1\leq s_1,s_2,s_3,s_4\leq 201≤s1​,s2​,s3​,s4​≤20。

1\leq A_1,A_2,\ldots,A_{s_1},B_1,B_2,\ldots,B_{s_2},C_1,C_2,\ldots,C_{s_3},D_1,D_2,\ldots,D_{s_4}\leq601≤A1​,A2​,…,As1​​,B1​,B2​,…,Bs2​​,C1​,C2​,…,Cs3​​,D1​,D2​,…,Ds4​​≤60。

我还没有学贪心算法,看题解的时候很多人用了贪心都没对,最后还是然我看到了dfs你永远可以相信dfs(当然得数据小大的请绕道看看bfs)

思路就是把情况都列举一遍,每道题目都给分别给左右脑子试试,每一条分支都会有一个结果分支返回的时候与当前的min比较一下如果还小的话就令min等于这个。把所有的分支走完就会得到最短得时间,再加到总时间里面去。

上码!

#include<stdio.h>
int a[21]={0};
int i=0;
int s[4];
int min;
int R=0,L=0;//两个脑子
void ji(int x,int b){
if(x>=s[b]){
    if(min>(R>L?R:L))//比一康康是否比原来时间短
        min=R>L?R:L;//是的就取这个。
    return;
}
else{

R=R+a[x];
ji(x+1,b);
R=R-a[x];//还原
L=L+a[x];//方到另一个脑子康康
ji(x+1,b);
L=L-a[x];//还原拉

}
}
int main(){
int l;
scanf("%d%d%d%d",&s[0],&s[1],&s[2],&s[3]);
for(int y=0;y<4;y++){
       R=0,L=0;// 给脑子初始化到了下一科了。
    for(l=0;l<s[y];l++){
    scanf("%d",&a[l]);
    }
    min=9999;//初始化,不然你的min会是上次的原值
    ji(0,y);
    i=i+min;
}
printf("%d",i);
return 0;
}
R=R+a[x];
ji(x+1,b);
R=R-a[x];//还原
L=L+a[x];//方到另一个脑子康康
ji(x+1,b);
L=L-a[x];//还原拉

这里是这代码的精华需要完全理解如果理解的话那什么了,这对你就是小菜。 

报告长官 over! 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值