poj3177(Redundant Path)

蓝书P183

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=5005;
const int M=10005;
int first[N],dfn[N]={0},low[N],co[N],col=0,num=0;
struct node{
	int v,next,from; //from表示无向边的另一条边的编号(可以以2为首边编号,则第n条无向边存储在下标为n*2,n*2+1的有向边结构体中,用d[i]=d[i^1]=1标记这条无向边已被访问过) 
}e[M<<1];
bool vis[M<<1]={0};  //记录这条边是否被访问过 
int n,m,k=0,st[N],top=0,du[N]={0};
int read(){
	int s=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9'){ s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
	return s;
}
void add(int ui,int vi){
    e[++k].v=vi;e[k].next=first[ui];first[ui]=k;e[k].from=k+1;  //u到v那条边,另一条边在k+1 
    e[++k].v=ui;e[k].next=first[vi];first[vi]=k;e[k].from=k-1;  //v到u那条边,另一条边在k-1 
}
int min(int x,int y){ if(x<y) return x;return y;}
void tarjan(int u){
	low[u]=dfn[u]=++num;
	st[++top]=u;
	for(int i=first[u];i;i=e[i].next){
	   if(!vis[e[i].from]){     //如果是第一次访问这条无向边 
	      vis[i]=1;  
		  int v=e[i].v;
		  if(!dfn[v]) {    //如果v点未被访问过 
		     tarjan(v);
		     low[u]=min(low[u],low[v]);   
		  }
		  else low[u]=min(low[u],dfn[v]);
	  }
	  else vis[i]=1;   //第i条边已访问 
    }
    int i;
    if(low[u]==dfn[u]){
    	col++;
    	do{
    		i=st[top--];
    		co[i]=col;   //将同一个强连通分量的点标记为痛 
    	}while(i!=u);
    }
}
void statis(){
	for(int i=1;i<=n;++i)
	  for(int j=first[i];j;j=e[j].next){
	  	 if(vis[e[j].from]){
	  	    int v=e[j].v;
	  	    if(co[i]!=co[v]){  //边为i到v,若两个结点不在同一个强连通分量中 
	  	    	du[co[i]]++;   //i结点所在的连通分量度加1 
	  	    	du[co[v]]++;   //v结点所在的连通分量度加1 
	  	    }
	  	 }
	  	 vis[j]=0;   //第j条边标记操作过 
	  }	  
	int t=0;      //t表示叶子结点个数 
	for(int i=1;i<=col;++i)
	  if(du[i]==1) t++;    //如果度为1,则叶子结点个数加1
	if(t==1) t=0;     //如果叶子结点数为1,则只需要增加0条边 
	printf("%d\n",(t+1)/2); 	
}
int main(){
	n=read();m=read();
	memset(first,0,sizeof(first));
	for(int i=1;i<=m;++i){
		int u=read(),v=read();
		add(u,v);
	}
	for(int i=1;i<=n;++i)
	  if(!dfn[i])	tarjan(i);
	statis();
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/weixin_44336566/article/details/89255681