zoukankan      html  css  js  c++  java
  • POJ2117 Electricity

    POJ2117 Electricity
    割点的题
    一开始觉得不难想水一发然后就去学别的,然后差点被特判恶心死
    其实还是挺水的

    求去掉某个点以及与其相连的边,最多可以形成多少个连通分量
    图可能不联通


    首先,tarjan 求出割点,求割点的同时,统计和这个割点相连的双连通分量有几个
    也就是代码中的 (cnt) 数组
    然后答案取 (max(cnt)),在加上联通块个数再减一就行了

    但是,如果所有联通块,分别多是一整个双联通分量,这样就会出问题

    • 如果存在一个大小大于一的联通块,那么答案肯定就是联通块的个数(其实这种情况直接按上面的方法来不特判也可以)
    • 但如果所以联通块的个数都是一,就不行了,去掉一个点后,会使联通块个数减少一个,那么答案就是联通块个数减一
    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<map>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    #define N 100006
    #define M 1000006
    struct graph{
    	int fir[N],nex[M],to[M],tot;
    	inline void add(int u,int v){
    		to[++tot]=v;
    		nex[tot]=fir[u];fir[u]=tot;
    	}
    	inline void clear(){
    		std::memset(fir,0,sizeof fir);tot=0;
    		std::memset(to,0,sizeof to);std::memset(nex,0,sizeof nex);
    	}
    }G;
    int n,m;
    int dfn[N],low[N],dfscnt;
    int cnt[N],size[N];
    void tarjan(int u,int is_root){
    	dfn[u]=low[u]=++dfscnt;
    	for(reg int v,i=G.fir[u];i;i=G.nex[i]){
    		v=G.to[i];
    		if(!dfn[v]){
    			tarjan(v,0);
    			low[u]=std::min(low[u],low[v]);
    			if(low[v]>=dfn[u]) cnt[u]++;
    		}
    		else low[u]=std::min(low[u],dfn[v]);
    	}
    	if(is_root) cnt[u]--;
    }
    int main(){
    	n=read();m=read();
    	while(n){
    		for(reg int u,v,i=1;i<=m;i++){
    			u=read()+1;v=read()+1;
    			G.add(u,v);G.add(v,u);
    		}
    		int block=0;
    		for(reg int i=1;i<=n;i++)if(!dfn[i]){
    			size[i]=dfscnt;
    			block++;tarjan(i,1);
    			size[i]=dfscnt-size[i];
    		}
    		int ans=0;
    		for(reg int i=1;i<=n;i++)if(cnt[i]) ans=std::max(ans,cnt[i]+1);
    		if(!ans){//特判每个联通分量都是双联通分量的情况 
    			int flag=0;//记录有没有一个联通分量大小大于一 
    			for(reg int i=1;i<=n;i++)if(size[i]>1){
    				flag=1;break;
    			}
    			if(flag) std::printf("%d
    ",block);
    			else std::printf("%d
    ",block-1);//大小全都是 1 
    		}
    		else std::printf("%d
    ",ans+block-1);
    		n=read();m=read();G.clear();
    		std::memset(dfn,0,sizeof dfn);std::memset(low,0,sizeof low);
    		std::memset(cnt,0,sizeof cnt);dfscnt=0;
    	}
    	return 0;
    }
    
  • 相关阅读:
    Eclipse配置Lifery SDK步骤与错误解决。
    Java Math floor round ceil 函数
    jpa多表leftjoin 查询,自定义返回结果
    saml2协议sp-initial登录过程
    httpclientutil
    解决samlexception-inresponsetofield-of-the-response-doesnt-correspond-to-sent-mess
    spring boot 整合saml2
    使用redis防止重复提交
    mysql转化时间戳毫秒到秒
    javamail 附件以及正文加图片
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12792681.html
Copyright © 2011-2022 走看看