HDU4587 TWO NODES(割点)

HDU4587 TWO NODES(割点)

Description
Suppose that G is an undirected graph, and the value of stab is defined as follows:
Among the expression,G -i, -j is the remainder after removing node i, node j and all edges that are directly relevant to the previous two nodes. cntCompent is the number of connected components of X independently.
Thus, given a certain undirected graph G, you are supposed to calculating the value of stab.
Input
The input will contain the description of several graphs. For each graph, the description consist of an integer N for the number of nodes, an integer M for the number of edges, and M pairs of integers for edges (3<=N,M<=5000).
Please note that the endpoints of edge is marked in the range of [0,N-1], and input cases ends with EOF.
Output
For each graph in the input, you should output the value of stab.
Sample Input
4 5 0 1 1 2 2 3 3 0 0 2
Sample Output
2

题意

从无向图中选两个点从图中删掉,求剩下的最大连通分量个数。
先枚举需要删去的第一个点i,再枚举需要删去的第二个点j,进行tarjan(j,-1)。iscut从是否为割点的意思更改为被标记为割点的次数,也就是子树的个数。则非根结点,子树的个数就是iscut,而根节点应该是iscut-1。
对于根节点的连通分量是孩子数目减1,因为跑一次Tarjan就是一个连通分量,如果你删掉这个Tarjan生成树的根节点实际上连通分量不增加。相当于一条手链从头部拿掉一个珠子变成了一条手链 + 一颗珠子(删除的割点)。
对于非树根节点删掉割点会增加一个连通分量。相当于一条手链从中间挖掉一个珠子就变成了两条链 + 1个珠子(删除的割点)。
这里的手链就是相当于一串珠子,没有围城环。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) ((x)&-(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e5+10,NN=2e3+10,INF=0x3f3f3f3f,LEN=20;
const ll MOD=1e9+7;
const ull seed=31;
inline int read(){
     
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
     
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
     
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
struct Edge{
     
	int next,to;
}edge[N];
int n,m,num_edge,dfn,del;
int head[N],num[N],low[N],iscut[N];//iscut为遍历时成为割点的次数 
void add_edge(int from,int to){
     
	edge[num_edge].next=head[from];
	edge[num_edge].to=to;
	head[from]=num_edge++;
}
void tarjan(int u,int fa){
     
	num[u]=low[u]=++dfn;
	for(int i=head[u];i!=-1;i=edge[i].next){
     
		int v=edge[i].to;
		if(v==del||v==fa) continue;//v==del需要跳过是因为del是第一个删除掉的点,v==fa需要跳过是因为v!=fa确保了(u,v)是从u到v的反向边
		if(!num[v]){
     
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>=num[u]) ++iscut[u];
		}
		else if(num[v]<num[u]) low[u]=min(low[u],num[v]);
	}
	if(fa==-1) --iscut[u];//根结点没有父结点,所以要减1 
}
void init(){
     
	num_edge=0;
	memset(head,-1,sizeof head);
	memset(low,0,sizeof low);
}
int main(){
     
	while(~scanf("%d%d",&n,&m)){
     
		init();
		for(int i=1;i<=m;i++){
     
			int u,v;
			scanf("%d%d",&u,&v);
			add_edge(u,v);
			add_edge(v,u);
		}
		int ans=-INF;
		for(int i=0;i<n;i++){
     
			int sum=0;
			memset(num,0,sizeof num);
			memset(iscut,0,sizeof iscut);
			dfn=0;del=i;
			for(int j=0;j<n;j++){
     
				if(j!=i&&!num[j]){
     
					++sum;
					tarjan(j,-1);
				}
			}
			int maxcut=-1; 
			for(int j=0;j<n;j++) if(j!=i) maxcut=max(maxcut,iscut[j]);
			ans=max(ans,maxcut+sum);
		}
		printf("%d\n",ans);
	}
}

你可能感兴趣的:(割点,C++)