题意:给出n个点和m条边的无向图,存在重边,问加一条边以后,剩下的桥的数量最少为多少。
题解:
你把这个无向图缩点后会得到一个只由桥来连接的图(可以说这个图中的所有边都是桥,相当于一棵树),然后我们只需要找出来这棵树的最大直径(即相距最远的两个点)。然后我们可以把得到的这条链的首尾两端连起来,因为这样减少的桥最多。把所有桥减去这条链上的桥就是答案
找树的直径有两种方法,一种树形dp,一种两次dfs算法。时间复杂度都是O(n)
先说dfs:
实现:随意选取一个点作为我们的起点x,找到以x为起点的和它是最远距离的另一个端点y,然后再以y为起点找到和它是最远距离的另一个端点z,这个y->z就是树的最大直径
本题代码1就是采用的这种解法
再说树形dp:
缺点:无法找到它的直径具体路径
优点:只需一遍遍历
实现:
1 //选取任意结点为根遍历树,设dis[i]:表示结点i为根的子树结点最远距离。 2 //则有: 3 //u为根的子树结点最远距离dis[u]=max(dis[u],dis[u]+W(u-v)) v是u的子节点 4 //最后直径即为根结点的两个最远距离之和 5 int dis[maxn],len=0; 6 void DP(int u,int pre) 7 { 8 dis[u]=0; //初始为0 9 for(int i=head[u];i!=-1;i=e[i].next) 10 { 11 int v=e[i].v,w=e[i].w; 12 if(v==pre) 13 continue; 14 DP(v,u); 15 len=max(len,dis[u]+dis[v]+w); //更新直径 16 dis[u]=max(dis[u],dis[v]+w); 17 } 18 }
代码1:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<map> 6 #include<vector> 7 using namespace std; 8 const int maxn=200005; 9 vector<int>w[maxn]; 10 int head[maxn],cnt,num,stacks[maxn],top,cut,in[maxn],out[maxn],pos,ci; 11 struct edge 12 { 13 int v,nnn; 14 } e[2000005]; 15 int visit[maxn],belong[maxn],dfn[maxn],low[maxn]; 16 void add_edge(int x,int y) 17 { 18 e[cnt].v=y; 19 e[cnt].nnn=head[x]; 20 head[x]=cnt++; 21 } 22 void init() 23 { 24 memset(low,0,sizeof(low)); //这里忘记初赋值了,卧槽 25 memset(dfn,0,sizeof(dfn)); 26 memset(head,-1,sizeof(head)); 27 cnt=num=top=cut=ci=0; 28 pos=-1; 29 } 30 void tarjan(int x,int pre) 31 { 32 low[x]=dfn[x]=++num; 33 visit[x]=1; 34 stacks[top++]=x; 35 int flag=1; 36 for(int i=head[x]; i!=-1; i=e[i].nnn) 37 { 38 int v=e[i].v; 39 if(v==pre && flag) 40 { 41 flag=0; 42 continue; 43 } 44 if(!dfn[v]) 45 { 46 tarjan(v,x); 47 low[x]=min(low[x],low[v]); 48 } 49 else if(visit[v]) 50 { 51 low[x]=min(low[x],dfn[v]); 52 } 53 } 54 if(low[x]==dfn[x]) 55 { 56 cut++; 57 int v; 58 while(true) 59 { 60 v=stacks[top-1]; 61 top--; 62 belong[v]=cut; 63 visit[v]=0; 64 if(v==x) break; 65 //printf("*"); 66 } 67 } 68 } 69 void dfs(int x,int t) 70 { 71 if(ci<t) 72 { 73 ci=t; 74 pos=x; 75 } 76 visit[x]=1; 77 int len=w[x].size(); 78 for(int i=0;i<len;++i) 79 { 80 int v=w[x][i]; 81 if(visit[v]) continue; 82 dfs(v,t+1); 83 } 84 } 85 int main() 86 { 87 int n,m; 88 while(~scanf("%d%d",&n,&m) && (n+m)) 89 { 90 init(); 91 while(m--) 92 { 93 int x,y; 94 scanf("%d%d",&x,&y); 95 add_edge(x,y); 96 add_edge(y,x); 97 } 98 tarjan(1,-1); 99 for(int i=1;i<=cut;i++) 100 w[i].clear(); 101 for(int i=1;i<=n;++i) 102 { 103 for(int j=head[i];j!=-1;j=e[j].nnn) 104 { 105 int v=e[j].v; 106 int fx=belong[i]; 107 int fy=belong[v]; 108 if(fx!=fy) 109 { 110 w[fx].push_back(fy); 111 w[fy].push_back(fx); 112 } 113 } 114 } 115 memset(visit,0,sizeof(visit)); 116 dfs(1,0); 117 memset(visit,0,sizeof(visit)); 118 ci=0; 119 dfs(pos,0); 120 printf("%d ",cut-ci-1); 121 } 122 return 0; 123 }
代码2:
1 //time 1031MS 2 3 //memory 31340K 4 5 #pragma comment(linker, "/STACK:1024000000,1024000000") 6 7 #include <iostream> 8 9 #include <cstdio> 10 11 #include <cstdlib> 12 13 #include <cstring> 14 15 #define MAXN 300015 16 17 #define MAXM 4000015 18 19 using namespace std; 20 21 struct Edge{ 22 23 int v,nnn; 24 25 }e[MAXM],edge2[MAXM]; 26 27 int head[MAXN],en; 28 29 int head2[MAXN],en2; 30 31 int belong[MAXN],dfn[MAXN],low[MAXN],stacks[MAXN],top,num,scc; 32 33 int n,m; 34 35 bool vis[MAXN]; 36 37 void init() 38 39 { 40 41 memset(head,-1,sizeof(head)); 42 43 memset(vis,0,sizeof(vis)); 44 45 en = 0; 46 47 top = 0; 48 49 scc=num = 0;memset(dfn,0,sizeof(dfn)); 50 51 } 52 53 void addedge(int u,int v) 54 55 { 56 57 e[en].v = v; 58 59 e[en].nnn = head[u]; 60 61 head[u] = en++; 62 63 } 64 65 void addedge2(int u,int v) 66 67 { 68 69 edge2[en2].v = v; 70 71 edge2[en2].nnn = head2[u]; 72 73 head2[u] = en2++; 74 75 } 76 77 //void tarjan(int u,int fa) //这个tarjan算法也是可以用的 78 // 79 //{ 80 // 81 // dfn[u] = low[u] = ++num; 82 // 83 // stacks[++top] = u; 84 // 85 // int cnt=0; 86 // 87 // for(int i = head[u]; i != -1; i = e[i].nnn) 88 // 89 // { 90 // 91 // int v = e[i].v; 92 // 93 // if(!dfn[v]) 94 // 95 // { 96 // 97 // tarjan(v,u); 98 // 99 // low[u] = min(low[u],low[v]); 100 // 101 // } 102 // 103 // else if (fa==v) 104 // 105 // { 106 // 107 // if (cnt) low[u] = min(low[u],dfn[v]);//重边 108 // 109 // cnt++; 110 // 111 // } 112 // 113 // else low[u] = min(low[u],dfn[v]); 114 // 115 // } 116 // 117 // if(dfn[u]==low[u]) 118 // 119 // { 120 // 121 // int x; 122 // 123 // scc++; 124 // 125 // do 126 // 127 // { 128 // 129 // x = stacks[top--]; 130 // 131 // belong[x] = scc; 132 // 133 // }while(x!=u); 134 // 135 // } 136 // 137 //} 138 void tarjan(int x,int pre) 139 { 140 low[x]=dfn[x]=++num; 141 vis[x]=1; 142 stacks[top++]=x; 143 int flag=1; 144 for(int i=head[x];i!=-1;i=e[i].nnn) 145 { 146 int v=e[i].v; 147 if(v==pre && flag) 148 { 149 flag=0; 150 continue; 151 } 152 if(!dfn[v]) 153 { 154 tarjan(v,x); 155 low[x]=min(low[x],low[v]); 156 } 157 else if(vis[v]) 158 { 159 low[x]=min(low[x],dfn[v]); 160 } 161 } 162 if(low[x]==dfn[x]) 163 { 164 scc++; 165 int v; 166 while(true) 167 { 168 v=stacks[top-1]; 169 top--; 170 belong[v]=scc; 171 vis[v]=0; 172 if(v==x) break; 173 //printf("*"); 174 } 175 } 176 } 177 void build() 178 179 { 180 181 en2 = 0; 182 183 memset(head2,-1,sizeof(head2)); 184 185 for(int i = 1; i <= n; i++) 186 187 { 188 189 for(int j = head[i]; j!=-1; j = e[j].nnn) 190 191 { 192 193 int v = e[j].v; 194 195 if(belong[i]!=belong[v]) 196 197 addedge2(belong[i],belong[v]); 198 199 } 200 201 } 202 203 } 204 205 int ans; 206 207 int dfs(int u,int p) 208 209 { 210 211 int max1=0,max2=0; 212 213 for (int i=head2[u];i!=-1;i=edge2[i].nnn) 214 215 { 216 217 int v=edge2[i].v; 218 219 if (v==p) continue; 220 221 int tmp=dfs(v,u)+1; 222 223 if (max1<tmp) max2=max1,max1=tmp; 224 225 else if (max2<tmp) max2=tmp; 226 227 } 228 229 ans=max(ans,max1+max2); 230 231 return max1; 232 233 } 234 235 int main() 236 237 { 238 239 //freopen("/home/qitaishui/code/in.txt","r",stdin); 240 241 int u,v; 242 243 while(scanf("%d%d",&n,&m)&&(n+m)) 244 245 { 246 247 init(); 248 249 //cout<<n<<m<<endl; 250 251 for(int i = 0; i < m; i++) 252 253 { 254 255 scanf("%d%d",&u,&v); 256 257 if (v==u) continue; 258 259 addedge(u,v); 260 261 addedge(v,u); 262 263 //cout<<u<<" "<<v<<endl; 264 265 } 266 267 268 269 tarjan(1,-1); 270 271 build(); 272 273 ans=0; 274 275 dfs(1,-1); 276 277 printf("%d ",scc-ans-1); 278 279 } 280 281 return 0; 282 283 }