题意:在一张无向图中去掉每一个点问你连通分支有几个?输出排序前m大的。排序规则是先按连通分支数降序,再按结点标号升序。
思路:求割点的变通,我们知道在dfs树中除去根节点,若当前节点是割点,那么删去它所得到的连通分支数就是子树的数量+1,而对于根节点就等于子树的数量。所以我们在dfs求割点的时候一旦发现一个子树中的所有点都无法回溯到根节点以前的祖先我们就认为找到了删去它的一个连通分支cut[i]++就可以了。最后有序输出就行了。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cmath> 5 #include <cstring> 6 #include <algorithm> 7 #include <queue> 8 #include <stack> 9 #include <vector> 10 #define MP(a, b) make_pair(a, b) 11 #define PB(a) push_back(a) 12 13 using namespace std; 14 15 typedef long long ll; 16 typedef pair<int ,int> pii; 17 typedef pair<unsigned int, unsigned int> puu; 18 typedef pair<int ,double> pid; 19 typedef pair<ll, int> pli; 20 21 const int INF = 0x3f3f3f3f; 22 const double eps = 1e-6; 23 const int LEN = 10010; 24 int n, m, dfn[LEN], cut[LEN], low[LEN], dclock; 25 vector<int> Map[LEN]; 26 struct cmp{ 27 bool operator() (pii a, pii b){ 28 if(a.second!=b.second)return a.second<b.second; 29 else return a.first>b.first; 30 } 31 }; 32 33 void dfs(int u, int fa) 34 { 35 int child = 0, v; 36 dfn[u] = low[u] = dclock++; 37 for(int i=0, v=Map[u][0]; i<Map[u].size(); i++, v=Map[u][i]) 38 if(dfn[v]<0){ 39 dfs(v,u); 40 child ++; 41 low[u] = min(low[u], low[v]); 42 if((low[v] >= dfn[u] && fa>=0) || (child>1 && fa<0))cut[u]++; 43 }else if(dfn[v] < dfn[u] && v!=fa) low[u] = min(low[u], dfn[v]); 44 } 45 46 int main() 47 { 48 // freopen("in.txt", "r", stdin); 49 50 int a, b; 51 while(scanf("%d%d", &n, &m)!=EOF){ 52 if(!n && !m)break; 53 for(int i=0; i<LEN; i++)Map[i].clear(); 54 while(scanf("%d%d", &a, &b)!=EOF){ 55 if(a==-1 && b==-1)break; 56 Map[a].PB(b); 57 Map[b].PB(a); 58 } 59 memset(dfn, -1, sizeof dfn); 60 memset(cut, 0, sizeof cut); 61 dclock = 1; 62 dfs(0, -1); 63 priority_queue<pii, vector<pii>, cmp> q; 64 for(int i=0; i<n; i++) q.push(MP(i, cut[i])); 65 for(int i=0; i<m; i++){ 66 pii nv = q.top(); q.pop(); 67 nv.second++; 68 printf("%d %d\n", nv.first, nv.second); 69 } 70 printf("\n"); 71 } 72 return 0; 73 }