uva 10765 Doves and bombs(双联通分量)
题意:我读了一遍题,没读懂
给一个n个点联通的无向图,要求的是去掉图中的某个点后,所形成的连通块的个数。按形成的连通块的个数的从多到少 和 点的编号从大到小 输出前m个结果。
解题思路:
说到解题方法,就要说一下求双连通分量这个事。
我原来理解双连通分量,以为其形式必然会是 几个点围成一个环才能叫一个双连通分量。其实不然。
定义:在无向连通图中,如果删除该图的任何一个结点都不能改变该图的连通性,则该图为双连通的无向图。
如果有两个点a,b相连,那么a-b就是一个双联通分量。它符合上面的定义。并且在这个图中,其实有两条边,a-b和b-a。
这么看来,也就能理解我在输出一个图中所有的双连通分量时,那些并不构成环的有两个点组成的边也能作为一个双联通分量输出。 也才能理解为什么这道题目可以用求双连通分量的方法这么做
解题思路:
如果这个点是割点,这个点必然会出现在多个联通分量中。那么去掉这个点,会形成>=两个连通块。
如果不是割点,那去掉这个点并不会有更多的连通块出现。注意这个时候,应该是1个连通块而不是0个。
这样我们首先求出所有的连通分量保存下来(bcc[maxn]),然后遍历所有的双连通分量,对每一个双连通分量其中的每一个点都判断其是否为割点(iscut[x]),如果是,那么其形成的连通块个数就+1(ans[x].num++);
code:
#include<cstdio> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<vector> using namespace std; const int maxn = 10005; //int n,k; struct node{ int id; int num; bool operator<(const node et) const{ if(num != et.num) return num > et.num; else return id < et.id; } }ans[maxn]; int pre[maxn], iscut[maxn], bccno[maxn], dfs_clock, bcc_cnt; ///bccno 是每个节点所属的双连通分量的编号 ///bcc_cnt是双连通分量的个数 vector<int> G[maxn], bcc[maxn]; ///bcc[]数组记录了每一支双连通分量 struct Edge{ int u, v; }; stack<Edge> S; int dfs(int u, int fa){ int lowu = pre[u] = ++dfs_clock; int child = 0; for(int i=0; i<G[u].size(); i++){ int v = G[u][i]; Edge e = (Edge){u, v}; if(!pre[v]){ S.push(e); child++; int lowv = dfs(v, u); lowu = min(lowu, lowv); if(lowv >= pre[u]){ iscut[u] = true; bcc_cnt++; bcc[bcc_cnt].clear(); for(;;){ Edge x = S.top(); S.pop(); if(bccno[x.u] != bcc_cnt) { bcc[bcc_cnt].push_back(x.u); bccno[x.u] = bcc_cnt; } if(bccno[x.v] != bcc_cnt) { bcc[bcc_cnt].push_back(x.v); bccno[x.v] = bcc_cnt; } if(x.u == u && x.v == v) break; } } } else if(pre[v] < pre[u] && v != fa){ S.push(e); lowu = min(lowu, pre[v]); } } if(fa < 0 && child == 1) iscut[u] = 0; return lowu; } void find_bcc(int n){ memset(pre, 0, sizeof(pre)); memset(iscut, 0, sizeof(iscut)); memset(bccno, 0, sizeof(bccno)); dfs_clock = bcc_cnt = 0; for(int i=0; i<n; i++){ if(!pre[i]) dfs(i, -1); } } int n,k; void init(){ for(int i = 0; i < n; i++){ ans[i].id = i; ans[i].num = 0; G[i].clear(); } int u,v; while(scanf("%d%d",&u,&v)){ if(u == -1 && v == -1) break; G[u].push_back(v); G[v].push_back(u); } } void solve(){ find_bcc(n); // printf("%d\n", bcc_cnt); ///双连通分量的个数 // for(int i=1; i<=bcc_cnt; i++){ ///输出每个双连通分量 // for(int j=0; j<bcc[i].size(); j++){ // printf("%d ", bcc[i][j]); // } // putchar('\n'); // } // printf("\n"); for(int i = 1; i <= bcc_cnt; i++){ for(int j = 0; j < bcc[i].size(); j++){ int x = bcc[i][j]; if(iscut[x]){ ans[x].num++; } } } sort(ans,ans+n); for(int i = 0; i < k; i++){ if(ans[i].num == 0) ans[i].num++; printf("%d %d\n",ans[i].id,ans[i].num); } } int main(){ while(scanf("%d%d",&n,&k)){ if(n == 0&&k == 0) break; init(); solve(); printf("\n"); } return 0; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。