题意:
给一个无向图,保证任意两个点之间有两条完全不相同的路径
求至少加多少边才能实现
题解:
得先学会一波tarjan无向图
桥的定义是:删除这条边之后该图不联通
一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足 DFN(u)<Low(v).(因为 v 想要到
达 u 的父亲必须经过(u,v)这条边,所以删去这条边,图不连通)
先用Tarjan无向图缩边双联通分量,这样原图就构成了一颗树,
对于树的叶子节点来说,显然他们需要连边,可以证明的是,我们连至多(叶子节点个数+1)/2的边就可以完成加边(叶子节点两两相连)
所以答案就是(叶子节点个数+1)/2
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define N 5010 5 #define M 10100 6 using namespace std; 7 int head[N],cut[M],n,m,ecnt=2,u,v,dfn[N],low[N],indx,fa[N],du[N],ans; 8 struct edge 9 { 10 int u,v,nxt; 11 }e[M*2]; 12 inline int find(int x) 13 { 14 return fa[x]=fa[x]==x?x:find(fa[x]); 15 } 16 void add(int u,int v) 17 { 18 e[ecnt].v=v; 19 e[ecnt].nxt=head[u]; 20 e[ecnt].u=u; 21 head[u]=ecnt++; 22 e[ecnt].v=u; 23 e[ecnt].nxt=head[v]; 24 e[ecnt].u=v; 25 head[v]=ecnt++; 26 } 27 void dfs(int u,int E) 28 { 29 dfn[u]=low[u]=++indx; 30 for (int i=head[u];i;i=e[i].nxt) 31 { 32 if (i==(E^1)) continue; 33 int v=e[i].v; 34 if (!dfn[v]) 35 { 36 dfs(v,i); 37 if (low[v]<low[u]) low[u]=low[v]; 38 if (low[v]>dfn[u]) cut[i]=cut[i^1]=1; 39 } 40 else 41 if (dfn[v]<low[u]) 42 low[u]=dfn[v]; 43 } 44 } 45 int main() 46 { 47 scanf("%d%d",&n,&m); 48 for (int i=1;i<=m;i++) 49 { 50 scanf("%d%d",&u,&v); 51 add(u,v); 52 } 53 dfs(1,-1); 54 for (int i=1;i<=n;i++) 55 fa[i]=i; 56 for (int i=2;i<ecnt;i+=2) 57 if (!cut[i]) fa[find(e[i].u)]=find(e[i].v); 58 for (int i=2;i<ecnt;i+=2) 59 if (cut[i]) du[find(e[i].u)]++,du[find(e[i].v)]++; 60 for (int i=1;i<=n;i++) 61 if (find(i)==i && du[i]==1) ans++; 62 printf("%d",(ans+1)/2); 63 return 0; 64 }
时间: 2024-11-05 11:24:57