HDU 4587 TWO NODES(割点 模板题)

题目描述


计算这个东西,即求删去两个点之后,的最大连通分量数.
3n,m5e3

分析

其实就是一道模板题,枚举每一个要删去的点,然后计算剩余点的连通分量数,删掉一个对ans贡献最大的,即删掉它之后能够增加最大的连通分量数目.

AC code


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define pb push_back
#define mp make_pair
#define PI acos(-1)
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int MOD = 1e9+7;
const int MAX_P = 2e4+10;
const int maxn = 5000+10;
const int MAX_V = 5e5+10;
typedef long long LL;
typedef long double DB;
typedef pair<double,double> Pair;

struct Edge{
    int from,to;
    int qiao;//桥边标识:1:桥,-1:重边不可能是桥,0:初始状态.
};
Edge E[maxn*2];
int ne = 0;
std::vector<int> G[maxn];
void add_egde(int u,int v,int qiao = 0){//重边影响
    E[ne++] = Edge{u,v,qiao};
    G[u].pb(ne-1);
    E[ne++] = Edge{v,u,qiao};
    G[v].pb(ne-1);
}
bool no_use[maxn];//禁止使用的节点
//求割点和桥;
//判断重边可以开个map来判断.然后置为-1
int dfs_clock = 0;//时间戳
int pre[maxn];//顶点的访问顺序
int low[maxn];//子树的最低访问时间
int cut[maxn];//割点后能增加的联通分量数
void init(){
    memset(pre,0,sizeof(pre));
    memset(cut,0,sizeof(cut));
    dfs_clock = 0;
}
//只能跑一个连通分量中的割点
void dfs(int u,int fa){
    low[u] = pre[u] = ++dfs_clock;
    int cl = 0;//孩子数目
    for(int i=0 ; iint v = e.to;
        if(no_use[v])continue;
        if(!pre[v]){
            cl++;
            dfs(v,u);
            low[u]= min(low[u],low[v]);
            //判断割点
            if(low[v] >= pre[u])cut[u]++;//增加(u,v)的联通集
            //判断割边
            if(low[v] > pre[u] && e.qiao !=-1)e.qiao = 1;
        }else if(pre[v] < pre[u] && v != fa){
            low[u] = min(low[u],pre[v]);
        }
    }
    if(fa == -1 && cl == 1)cut[u] = 0;//根节点
}
int n,m;

int main() {

    while (scanf("%d%d",&n,&m) != EOF) {
        for(int i=0 ; i0;
        memset(no_use,0,sizeof(no_use));
        int ans =0 ;
        while (m--) {
            int u,v;
            scanf("%d%d",&u,&v );
            add_egde(u,v);
        }

        for(int i=0 ; i1;
            int now_ans =0;
            dfs_clock = 0;
            for(int j=0 ; j0,cut[j] =1;
            for(int j =0 ; jif(j!=i && !pre[j]){
                    ++now_ans;
                    cut[j] = 0;
                    dfs(j,-1);
                }
            }
            int acc = *max_element(cut,cut+n);
            if(now_ans == n-1)now_ans--;
            else if(acc >0)now_ans +=acc-1;

            ans = max(now_ans,ans);
            no_use[i] = 0;
        }
        printf("%d\n",ans );
    }

    return 0;
}

总结

这是割点的第一道题,有如下收获:

  • 计算删去之后的连通分量只需在判断割点的时候将判断改成加就行了.

  • 计算时由于仅是对时间戳小于当前顶点的值的增加(即是子节点连通分量的增加),需要在初始化的时候将cut设为1,默认父节点是会增加的.

  • 特殊情况.当图由全部的孤立点组成时,ans-1

你可能感兴趣的:(算法&数据结构)