题目链接: http://poj.org/problem?id=2117
题目大意:在一个非连通图中,求一个切除图中任意一个割点方案,使得图中连通分量数最大。
解题思路:
一个大陷阱,m可以等于0,这时候要特判,结果就是n-1。
同时出题者脑子秀逗了,也不给C的范围。我开了两倍点大小RE了,于是怒开了五倍点大小才A了。
本题不是连通图,需要先计算原始图中的连通分量。方法就是dfs染色。
然后dfs求割点。
之后枚举割点,由于是非连通图,所以连通分量数=原始分量数+block-1。
-1的原因是,每次相当于对其中一个连通分量计算,加上新的block之后,所以要减-1。
#include "cstdio" #include "cstring" #include "vector" using namespace std; #define maxn 10005 struct Edge { int to,next; }e[maxn*5]; int dfs_clock,pre[maxn],block,head[maxn],tol; bool cut[maxn],vis[maxn]; void addedge(int u,int v) { e[tol].to=v; e[tol].next=head[u]; head[u]=tol++; } int dfs(int u,int fa) { int lowu=pre[u]=++dfs_clock; int child=0; for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].to; if(!pre[v]) { int lowv=dfs(v,u); lowu=min(lowu,lowv); if(lowv>=pre[u]) cut[u]=true; } else if(pre[v]<pre[u]&&v!=fa) lowu=min(lowu,pre[v]); } if(fa<0&&child==1) cut[u]=false; return lowu; } void check(int u,int fa) { vis[u]=true; for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].to; if(!vis[v]) { if(u==fa) block++; check(v,fa); } } } void link(int u) //判断初始连通分量 { vis[u]=true; for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].to; if(!vis[v]) link(v); } } int main() { //freopen("in.txt","r",stdin); int n,m,u,v; while(scanf("%d%d",&n,&m)&&n) { memset(head,-1,sizeof(head)); memset(pre,0,sizeof(pre)); memset(cut,false,sizeof(cut)); dfs_clock=0;tol=0; if(m==0) printf("%d ",n-1); //特判 else { for(int i=1; i<=m; i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } int res=0,tt=0; for(int i=0; i<n; i++) if(!vis[i]) {tt++;link(i);} memset(vis,false,sizeof(vis)); for(int i=0; i<n; i++) if(!pre[i]) dfs(i,-1); res=tt; for(int i=0; i<n; i++) { if(cut[i]) { check(i,i); if(tt) res=max(res,block+tt-1); block=0; memset(vis,false,sizeof(vis)); } } printf("%d ",res); } } }
2905876 | neopenx | POJ | 2117 | Accepted | 732 | 2422 | C++ | 2129 |