Warm up HDU - 4612 树的直径

独自空忆成欢 提交于 2019-12-01 06:57:46

题意:给出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\n",cut-ci-1);
121     }
122     return 0;
123 }
View Code

 

代码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\n",scc-ans-1);
278 
279     }
280 
281     return 0;
282 
283 }
View Code

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!