tarjan求割点

洛谷P3388 【模板】割点(割顶)

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=100009;
struct node {
    int to,nxt;
} e[2*maxn];
int n,m,cnt=0,index=0,head[maxn],dfn[maxn],low[maxn],iscut[maxn],ans=0;
void add(int u,int v) {
    e[++cnt].to=v;
    e[cnt].nxt=head[u];
    head[u]=cnt;
}
void tarjan(int u,int fa) {
    int child=0;
    dfn[u]=low[u]=++index;
//	cout<<"dfs  "<<dfn[u]<<" "<<low[u]<<endl;
    for(int i=head[u]; i>0; i=e[i].nxt) {
        int v=e[i].to;
        if(!dfn[v]) {
            child++;
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(fa>0&&low[v]>=dfn[u]) {
                if(!iscut[u])++ans;//一个顶点可能被标记多次
                iscut[u]=1;
                //	cout<<"df u"<<u<<" ans"<<ans<<endl;
            }

        } else if(dfn[v]<dfn[u]&&v!=fa)
            low[u]=min(low[u],dfn[v]);
    }
    //cout<<u<<"  child  "<<child<<endl;
    if(fa<0&&child>1) {
        //if(!iscut[u])
        ++ans;//根节点不可能被统计多次
        iscut[u]=1;
        //	cout<<"fa "<<u<<endl;
    }

}
int main() {
    cin>>n>>m;
    int u,v;
    for(int i=1; i<=m; i++) {
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    for(int i=1; i<=n; i++)
        if(!dfn[i])tarjan(i,-1);
    printf("%d\n",ans);
    for(int i=1; i<=n; i++)
        if(iscut[i])cout<<i<<" ";
}

poj2117,题目大意,给定一个图,删除一个点后,最多有多少连通块。
三种情况:
1:所有点是独立点,总数-1;
2:没有割点
3:删除链接儿子数最多的割点。
参考代码:
#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
const int maxn=10009;
struct node {
	int to,nxt;
} e[20*maxn];
int n,m,cnt=0,index=0,head[maxn],dfn[maxn],low[maxn],iscut[maxn],ans=0;
void add(int u,int v) {
	e[++cnt].to=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
int tarjan(int u,int fa) {
	int child=0;
	dfn[u]=low[u]=++index;
//	cout<<"dfs  "<<dfn[u]<<" "<<low[u]<<endl;
	for(int i=head[u]; i>0; i=e[i].nxt) {
		int v=e[i].to;
		if(!dfn[v]) {
			child++;
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(fa>0&&low[v]>=dfn[u])
				iscut[u]++;
		} else if(dfn[v]<dfn[u]&&v!=fa)
			low[u]=min(low[u],dfn[v]);
	}
	//cout<<u<<"  child  "<<child<<endl;
	if(fa<0) 
		iscut[u]=child-1;
	return 0;
}
int main() {
	while(scanf("%d%d",&n,&m)==2) {
		if(n==0&&m==0)return 0;
		memset(head,0,sizeof(head));
		memset(e,0,sizeof(e));
		memset(iscut,0,sizeof(iscut));
		memset(dfn,0,sizeof(dfn));
		memset(low,0,sizeof(low));
		int u,v;
		cnt=0;
		for(int i=1; i<=m; i++) {
			scanf("%d%d",&u,&v);
			++u,++v;
			add(u,v);
			add(v,u);
		}
		int un=0;
		ans=-1;
		for(int i=1; i<=n; i++) {
			if(!dfn[i])tarjan(i,-1),un++;
		}
		for(int i=1; i<=n; i++)ans=max(ans,iscut[i]);
		cout<<un+ans<<endl;


	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值