冗余路径 Redundant Paths e-DCC缩点

冗余路径 Redundant Paths

题目传送

sol:

如果两点间存在至少两条不重复的路径,这说明他们两点在同一个边双连通分量(不存在割边)。

那么可以进行e-DCC的缩点,得到一棵树。

对于这棵树广泛意义上的叶子节点(度数为1)而言,都还至少需要一条边连向他。

那么可以贪心的一次连两个叶子节点,答案显然就是\(cnt+1>>1\)

#include<bits/stdc++.h>
#define IL inline
#define RG register
#define DB double
#define LL long long
using namespace std;

const int N=5005;
const int M=1e4+5;

int n,m,tot,cnt,leaf,Time,head[N],bel[N],vis[N],low[N],dfn[N],bri[M<<1];

struct edge{int x,y;}s[M];
struct EDGE{int next,to;}e[M<<1];

IL int gi() {
	RG int x=0,p=1; RG char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') p=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
	return x*p;
}

IL void New() {
	tot=0;
	memset(&e,0,sizeof(e));
	memset(head,0,sizeof(head));
}

IL void make(int a,int b) {
	e[++tot]=(EDGE){head[a],b},head[a]=tot;
	e[++tot]=(EDGE){head[b],a},head[b]=tot;
}

void Tarjan(int x,int fx) {
	RG int i,y;
	dfn[x]=low[x]=++Time;
	for(i=head[x];i;i=e[i].next) {
		if(!dfn[y=e[i].to]) {
			Tarjan(y,x),low[x]=min(low[x],low[y]);
			if(low[y]>dfn[x]) bri[i]=bri[i^1]=1; 
		}
		else if(y!=fx) low[x]=min(low[x],dfn[y]);
	}	
}

void dfs(int x) {
	RG int i,y;
	bel[x]=cnt,vis[x]=1;
	for(i=head[x];i;i=e[i].next)
		if(!vis[y=e[i].to]&&!bri[i]) dfs(y);
}

void dfs2(int x,int fx) {
	RG int i,y,fl=0;
	for(i=head[x];i;i=e[i].next)
		if((y=e[i].to)!=fx) fl=1,dfs2(y,x);
	if(!fl) ++leaf;
}

int main()
{
	RG int i,b=0;
	n=gi(),m=gi(),tot=1;
	for(i=1;i<=m;++i)
		s[i].x=gi(),s[i].y=gi(),make(s[i].x,s[i].y);
	for(i=1,Tarjan(1,0);i<=n;++i)
		if(!vis[i]) ++cnt,dfs(i);
	if(cnt==1) return puts("0"),0;
	for(i=1,New();i<=m;++i)
		if(bel[s[i].x]!=bel[s[i].y]) make(bel[s[i].x],bel[s[i].y]);
	dfs2(1,0);
	for(i=head[1];i;i=e[i].next) ++b;
	if(b==1) ++leaf;
	printf("%d\n",leaf+1>>1);
	return 0;
}
posted @ 2019-07-28 11:36  薄荷凉了夏  阅读(238)  评论(0编辑  收藏  举报