这道题的总体思路就是找到连通量让它能够看作一个集合,然后找这个集合的度,度数为1的连通量为k,那么需要添加(k+1)/2条边才可以保证边双连通
这里因为一个连通量中low[]大小是相同的,所以我们用ans[low[i]]++来计度数
这道题我最开始按学长的模板来写。。。。MLE到哭了,也不知道这道题为什么这么逗,把5000的数组改成1000也能过,当然后来换了别的思路
为了防止重边的进入,开始设置了一个hash[][]二维数组来判断边是否已经存在,不额外添入
之后,我不采用二维数组,而是在get_bcc函数中利用visit[]一维数组来防止重边的多次访问,也就是说我允许添入多个边,但我不让它多次被访问
这样每循环一次,我就需要更新一次数组,但是空间耗费少了特别多还是很好的。
自己修改多次的代码:
#include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; #define N 5005 int k,n,first[N],tmpdfn,dfn[N],low[N],cnt;//isBridge[][]用来判断是否为桥,cnt记载桥的个数 struct Path{ int y,next; }path[2*N]; void add(int x,int y) { path[k].y=y,path[k].next=first[x]; first[x]=k; k++; } void dfs(int u,int fa) { dfn[u]=low[u]=++tmpdfn; for(int i=first[u];i!=-1;i=path[i].next){ int v=path[i].y; if(!dfn[v]){ dfs(v,u); low[u]=min(low[u],low[v]); } else if(v!=fa) low[u]=min(low[u],dfn[v]); } } void get_bcc(int n) { int visit[N]; cnt=0; int ans[N]; memset(ans,0,sizeof(ans)); for(int i=1;i<=n;i++){ if(!dfn[i]) dfs(n,-1); } for(int i=1;i<=n;i++){ memset(visit,0,sizeof(visit)); for(int j=first[i];j!=-1;j=path[j].next){ int v=path[j].y; if(low[i]!=low[v]&&!visit[v]) ans[low[i]]++,visit[v]=1; } } for(int i=1;i<=n;i++) if(ans[i]==1) cnt++; } int main() { int R,x,y; while(scanf("%d%d",&n,&R)!=EOF){ tmpdfn=0,k=0; memset(dfn,0,sizeof(dfn)); memset(first,-1,sizeof(first)); for(int i=0;i<R;i++){ scanf("%d%d",&x,&y); add(x,y); add(y,x); } get_bcc(n); printf("%d ",(cnt+1)/2); } return 0; }
学长的代码,作为模版还是很有价值的:
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #define maxn 1010 using namespace std; int pre[maxn],dfs_clock,isbridge[maxn][maxn]; vector<int> G[maxn]; bool hash[maxn][maxn]; int dfs1(int u,int fa){ int lowu = pre[u] = ++dfs_clock; for(int i = 0;i < G[u].size();i++){ int v = G[u][i]; if(!pre[v]){ int lowv = dfs1(v,u); lowu = min(lowu,lowv); if(lowv > pre[u]){ isbridge[u][v] = isbridge[v][u] = 1; } }else if(pre[v] < pre[u] && v != fa){ lowu = min(lowu,pre[v]); } } return lowu; } int fa[maxn],vis[maxn]; int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);} void dfs2(int u){ for(int i = 0;i < G[u].size();i++){ int v = G[u][i]; if(!vis[v] && !isbridge[u][v]){ int x = find(u);int y = find(v); if(x != y) fa[x] = y; vis[v] = 1; dfs2(v); } } } void find_bcc(int n){ memset(pre,0,sizeof(pre)); memset(isbridge,0,sizeof(isbridge)); dfs_clock = 0; for(int i = 0;i < n;i++) if(!pre[i]) dfs1(i,-1); for(int i = 0;i < n;i++){ if(!vis[i]){ vis[i] = 1; dfs2(i); } } } int degree[maxn]; bool used[maxn]; int main() { int n,m; while(scanf("%d%d",&n,&m) == 2){ for(int i = 0;i < n;i++){ fa[i] = i; G[i].clear(); } memset(hash,0,sizeof(hash)); for(int i = 0;i < m;i++){ int a,b; scanf("%d%d",&a,&b); a--;b--; if(!hash[a][b]){ G[a].push_back(b); G[b].push_back(a); hash[a][b] = hash[b][a] = 1; } } find_bcc(n); memset(degree,0,sizeof(degree)); memset(used,0,sizeof(used)); for(int i = 0;i < n;i++) for(int j = 0;j < G[i].size();j++){ if(find(i) != find(G[i][j])) degree[find(G[i][j])]++; } int sum = 0; for(int i = 0;i < n;i++){ int x = find(i); if(!used[x]){ used[x] = 1; if(degree[x] == 1) sum++; else if(degree[x] == 0) sum += 2; } } int cnt = 0; for(int i = 0;i < n;i++){ if(used[i] == 1) cnt++; } if(cnt == 1) printf("0 "); else printf("%d ",(sum+1)/2); } return 0; }