首页 > 其他分享 >Living-Dream 系列笔记 第10期

Living-Dream 系列笔记 第10期

时间:2024-03-09 12:35:16浏览次数:18  
标签:Living 连通 10 int text 31 dfs && Dream

本期主要讲解进阶 \(\text{DFS}\)。

知识点

\(\text{DFS}\) 求解连通块问题:

  • 定义:若一个点集中的所有点都能互达,且与集合外的点无法互达,则称此点集为一个连通块。

  • 考查方式:求连通块数量 / 大小 / 周长。

例题

T1

在 \(\text{DFS}\) 函数中传入参数 \(x\) 和 \(str\),分别表示当前字符串的长度和当前字符串。

每次搜索都遍历所有可用字符串,不断尝试进行拼接,若新增长度 \(>0\) 且字符串使用次数 \(<2\),则继续进行下一层搜索。

#include<bits/stdc++.h>
using namespace std;

int n,ans=-1e9;
string str[31];
int vis[31];
string ch;

int match(string a,string b){
    if(a.size()==1){
        if(a[0]==b[0]) return b.size();
        return 0;
    }
    for(int i=1;i<min(a.size(),b.size());i++){
        string t1=a.substr(a.size()-i),t2=b.substr(0,i);
        if(t1==t2) return b.size()-i;
    }
    return 0;
}
void dfs(int x,string s){
    ans=max(ans,x);
    for(int i=1;i<=n;i++){
        int len=match(s,str[i]);
        if(len>0&&vis[i]<2){
            vis[i]++;
            dfs(x+len,str[i]);
            vis[i]--;
        }
    }
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>str[i];
    cin>>ch;
    dfs(0,ch);
    cout<<ans;
    return 0;
}

T2

初始坐标为 \((0,0)\),若扩展后坐标合法,则不断 \(\text{DFS}\) 向右进行扩展,当到达 \((m,n)\) 时就将方案数 \(ans \gets ans+1\) 即可。

#include<bits/stdc++.h>
using namespace std;

int n,m,total;
int dx[]={1,1,2,2},dy[]={2,-2,1,-1};

void dfs(int x,int y){
    if(x==m&&y==n){
        total++; return;
    }
    for(int i=0;i<4;i++){
        int xx=x+dx[i],yy=y+dy[i];
        if(xx>=0&&xx<=m&&yy>=0&&yy<=n) dfs(xx,yy);
    }
}

int main(){
    cin>>n>>m;
    dfs(0,0);
    cout<<total;
    return 0;
}

习题

T3

求连通块数量的典题。

遍历整个矩阵,若当前点 \(a_{i,j} \neq 0\) 且未被访问,则从此处开始 \(\text{DFS}\)。

在搜索过程中,我们先将连通块总数 \(sum \gets sum+1\),然后不断尝试从当前点出发向四个方向扩展,若有一个方向的点也 \(\neq 0\),则标记此点并继续搜索。

若当前点是不合法的,说明连通块遍历完成,直接结束搜索。

#include<bits/stdc++.h>
using namespace std;
int n,m,ans,cell[131][131],dx[]={-1,0,1,0},dy[]={0,-1,0,1};
void dfs(int x,int y){
    if(x>n||y>m||x<0||y<0) return;
    cell[x][y]=0;
    for(int i=0;i<4;i++)
        if(cell[x+dx[i]][y+dy[i]]) 
            dfs(x+dx[i],y+dy[i]);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            scanf("%1d",&cell[i][j]);
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(cell[i][j]) ans++,dfs(i,j);
        }
    }
    printf("%d",ans);
    return 0;
}

T4

直接找到起始点开始搜索,期间不断向安全地扩展即可。

#include<bits/stdc++.h>
using namespace std;

int n,m,sx,sy,sum;
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
char mp[31][31];
bool vis[31][31];

void dfs(int x,int y){
    for(int i=0;i<4;i++){
        int xx=x+dx[i],yy=y+dy[i];
        if(vis[xx][yy]==0&&mp[xx][yy]=='.'&&xx>=1&&xx<=n&&yy>=1&&yy<=m){
            vis[xx][yy]=1,sum++;
            dfs(xx,yy);
            //vis[xx][yy]=0,sum--;
        }
    }
}

int main(){
    cin>>m>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
        	cin>>mp[i][j];
            if(mp[i][j]=='@') sx=i,sy=j;
        }
    vis[sx][sy]=1,sum++;
    dfs(sx,sy);
    cout<<sum;
    return 0;
}

T5

读到一个 # 就开始搜索。

面积很好求,就是和 T3 一样求连通块个数。

周长就是如果当前点旁边若有一个点为 .,就令周长 \(c \gets c+1\)。

求出一个连通块后,根据题目规则更新全局最优答案即可。

#include<bits/stdc++.h>
using namespace std;

int n;
char ice[1031][1031];
int S,C,s,c;
bool vis[1031][1031];
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};

void update(){
    if(s>S) S=s,C=c;
    if(s==S&&c<C) C=c;
}
void dfs(int x,int y){
    if(vis[x][y]) return;
    vis[x][y]=1,s++;
    for(int i=0;i<4;i++){
        int xx=x+dx[i],yy=y+dy[i];
        if(xx<1||xx>n||yy<1||yy>n||ice[xx][yy]=='.') c++;
        if(ice[xx][yy]=='#') dfs(xx,yy);
    }
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            cin>>ice[i][j];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(ice[i][j]=='#'&&!vis[i][j]){
            	s=c=0;
                dfs(i,j);
                update();
            }
        }
    }
    cout<<S<<' '<<C;
    return 0;
}

标签:Living,连通,10,int,text,31,dfs,&&,Dream
From: https://www.cnblogs.com/XOF-0-0/p/18062516

相关文章

  • P10217 [省选联考 2024] 季风题解
    考场上没写出来,火大,实际上这题放校内%你赛我肯定写的出来,可惜这是省选。实际上这题不难,主要是观察性质,接着拆柿子,然后就是有点难写,要写得好看有点考验代码构建能力和数学能力。我们考虑原题的每对\((x,y)\)都要满足\(|x|+|y|\lek\)而我们可以知道后面应该填的\((x,y)\)如......
  • Living-Dream 系列笔记 第8期
    本期主要讲解的与上期相同。例题T1上课的时候调这个题感觉要吐了\(qwq\)。。。首先读入\(n\)行字符串,可以采取忽略中间无关单词的方式来直接读取\(X\)和\(Y\)。将所有名字存入\(a\)数组,对\(a\)数组按字典序排序后就可以开始\(\text{DFS}\)了,这里建议使用next_pr......
  • Living-Dream 系列笔记 第9期
    模拟赛掉大分(悲T1板子,不讲。T2首先很明显这题是个去重全排列。和模板的区别就是加了一个\(sum\)参数记录目前已经放了几个苹果。当\(x=n+1\)时若\(sum=m\),则更新答案。同时加入一个剪枝:若在搜索过程中\(sum>m\),则直接return结束搜索。#include<bits/stdc++.h>usi......
  • Living-Dream 系列笔记 第6期
    模拟赛。寄。T1对于每次询问,二分查找数组中对应值的原下标即可,因此需要用结构体存储原始数据和原始下标。这当然是比较麻烦的做法。另一种做法则是开一个map替代桶来存储数组中每个元素的下标,对于每个询问输出即可。另外值得注意的是,本题默认询问之间相互独立。时间复杂度......
  • Living-Dream 系列笔记 第7期
    本期主要讲解深度优先搜索\(\text{DFS}\)。知识点种类:全排列。可以想象为填格子。去重全排列,即组合。时间复杂度均为\(O(n!)\)。\(\text{DFS}\)题的特征:求方案总数/最值。数据范围极小(一般\(n\le20\))。无法直接暴力枚举(因为循环嵌套层数不确定)。......
  • Living-Dream 系列笔记 第4期
    本期主要讲解二分答案。知识点使用场景:最小值最大化,或最大值最小化。在限制条件下找最值。与二分查找的区别:L、R均为答案,而非下标。输出:最大化输出L,反之输出R。例题T1二分\(M\)的值,边界为\(L=-1,R=\max{\{a_i\}}\)。每次枚举到一个\(mid\)就对于每个......
  • Living-Dream 系列笔记 第5期
    本期主要讲解二分答案的进阶。例题T1二分需要的秒数,在check函数中对于每件衣服,若其在\(x\)秒内无法自然晒干,则使用烘干机,并令\(sum\)加上使用烘干机的秒数,最后判断\(sum\)是否\(\lex\)即可。\(Trick\):二分边界需要按数据范围尽可能开大,不能开小了。#include<bits/......
  • KBPC2510-ASEMI逆变器整流桥KBPC2510
    编辑:llKBPC2510-ASEMI逆变器整流桥KBPC2510型号:KBPC2510品牌:ASEMI封装:KBPC-4正向电流(Id):25A反向耐压(VRRM):1000V正向浪涌电流:300A正向电压(VF):1.00V引脚数量:4芯片个数:4芯片尺寸:MIL功率(Pd):大功率设备工作温度:-55°C~150°C类型:插件整流桥、整流方桥KBPC2510整流桥描述:......
  • GBU1510-ASEMI逆变器整流桥GBU1510
    编辑:llGBU1510-ASEMI逆变器整流桥GBU1510型号:GBU1510品牌:ASEMI封装:GBU-4最大重复峰值反向电压:1000V最大正向平均整流电流(Vdss):15A功率(Pd):大功率芯片个数:4引脚数量:4类型:插件整流桥、整流扁桥正向浪涌电流:200A正向电压:1.10V最大输出电压(RMS):封装尺寸:如图工作温度:-55......
  • MYSQL学习笔记10: DQL分页查询(利用limit)
    DQL分页查询(利用limit)select字段列表from表名limit起始索引,查询记录数;起始索引从0开始,起始索引=(查询页码-1)*每页显示记录数分页查询是数据库的方言,不同数据库有不同的实现,MYSQL中是LIMIT如果查询的是第一页的数据,起始索引可以省略,直接简写为l......