洛谷P3388 割点数量计算

本文介绍了一种算法,用于计算图中的割点数量及其具体位置。通过深度优先搜索(DFS)和Tarjan算法,实现对图中割点的识别与统计。文章详细解释了割点的概念,即拆除后会导致图不连通的点,以及如何通过子节点数量和low值来判断一个点是否为割点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/**
洛谷3388 计算割点的数量及割点
割点:拆点后图不连通的点 根:child>=2 非: low[v]>=dfn[u];
割桥:割点出度方向所连的边;一般用pair进行存储;
*/

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;

const int maxn=1e5+7;

int top,bcnt,dcnt;
int sta[maxn],dfn[maxn],low[maxn],belong[maxn];
bool ins[maxn];
int out[maxn];
int u,v,n,m;

std::vector<int> G[maxn];
std::vector<int> GG[maxn];

int parent[maxn];//节点关系;
int iscut[maxn];//当前节点是否为割点;
int cut_num;//割点数量;

void dfs(int u){
    dfn[u]=low[u]=++dcnt;
    ins[u]=true;
    sta[top++]=u;
    int child=0;
    for(int v:G[u]){
        if(dfn[v]==0) {
            child++;
            parent[v]=u;
            dfs(v);
            low[u]=min(low[u],low[v]);
            if((!iscut[u]&&parent[u]!=-1&&low[v]>=dfn[u])||(parent[u]==-1&&child>=2&&!iscut[u])) iscut[u]=1,cut_num++;
            //非根节点low[v]>=dfn[u];当前节点为根节点 且出度为2
        }
        else if(ins[v]) low[u]=min(low[u],dfn[v]);
    }

    /*******************************缩点操作部分 栈记录可能构成强联通分量的点**************/
    if(dfn[u]==low[u]) {
        ++bcnt;
        int pos;
        do{
            pos=sta[--top];
            ins[pos]=false;
            belong[pos]=bcnt;
        }while(pos!=u);
    }
    return ;
}

void tarjan(){
    bcnt=top=dcnt=cut_num=0;
    memset(dfn,0,sizeof(dfn));
    memset(ins,0,sizeof(ins));
    memset(out,0,sizeof(out));
    memset(iscut,0,sizeof(iscut));
    memset(parent,-1,sizeof(parent));
    for(int i=1;i<=n;i++) if(dfn[i]==0) dfs(i);

    /***缩点后图变为GG操作*********************************/
    for(int i=1;i<=n;i++) GG[i].clear();
    for(int i=1;i<=n;i++){
        for(int pos:G[i]){
            int u=belong[i];
            int v=belong[pos];
            if(u!=v) GG[u].push_back(v),++out[u];
        }
    }
}

int main () {
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d %d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    tarjan();
    printf("%d\n",cut_num);//割点的数量;
    for(int i=1;i<=n;i++) {
        if(iscut[i]){
            cut_num--;
            printf(cut_num==0?"%d\n":"%d ",i);
        }
    }
    return 0;
}

 

### 解决方案 对于洛谷平台上的编号为P1451的C++编程题——求细胞数量,该问题可以通过深度优先搜索(DFS)来解决。此方法适用于处理连通块问题,在这种情况下,“细胞”的定义是基于相邻位置(上、下、左、右)是否同样含有非零数值[^3]。 #### 代码实现 下面是一个使用DFS算法解决问题的具体实例: ```cpp #include <iostream> using namespace std; const int MAXN = 100; int n, m; // 行数n 和 列数m char grid[MAXN][MAXN]; // 存储输入矩阵 bool visited[MAXN][MAXN]; // 访问标记数组 // 方向数组,用于表示四个可能移动的方向:上、下、左、右 int dx[] = {-1, 1, 0, 0}; int dy[] = {0, 0, -1, 1}; void dfs(int x, int y){ visited[x][y] = true; // 标记当前位置已访问 for (int i = 0; i < 4; ++i){ // 尝试朝四个方向扩展 int nx = x + dx[i]; int ny = y + dy[i]; if(nx >= 0 && nx < n && ny >= 0 && ny < m && !visited[nx][ny] && grid[nx][ny]!='0'){ dfs(nx, ny); // 如果新坐标合法且未被访问,则递归调用dfs函数 } } } int main(){ cin >> n >> m; for(int i=0;i<n;++i) for(int j=0;j<m;++j) cin>>grid[i][j], visited[i][j]=false; int count = 0; for(int i=0;i<n;++i) for(int j=0;j<m;++j) if(!visited[i][j]&&grid[i][j]!='0'){ dfs(i,j); ++count; // 每找到一个新的连通区域即增加计数器 } cout << "The number of cells is: " << count << endl; } ``` 这段程序首先读取了一个大小为`n*m`的字符网格作为输入,并初始化了一个布尔类型的二维数组`visited[][]`用来跟踪哪些单元格已经被探索过了。接着遍历整个网格,每当遇到一个尚未访问过的‘活’细胞时,就会启动一次新的DFS过程并相应地增加细胞总数目。每次执行DFS都会尽可能多地沿着相连的路径前进直到无法再进一步为止。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值