树的直径(10)
2020-02-02 19:45
232 查看
树的直径
前面讲的那个BFS不知大家懂了没有,没关系,不懂慢慢理解吧,这也没有什么好办法。
这篇给大家讲一个板子内容。
先说一下树的直径是干嘛的,再上板子稳定军心:
树的直径就是求一棵树最远的俩个点的距离。方法就是两次dfs或bfs。第 一次任意选一个点进行dfs(bfs)找到离它远的点,此点就是最长路的一个端点,再以此点进行dfs(bfs),找到离它远的点,此点就是最长路的另一个端点,于是就找到了树的直径。
证明(想看的看一下,不想看可以不看)
假设此树的 长路径是从s到t,我们选择的点为u。
反证法:假设搜到的点是v。
1、v在这条最长路径上,那么dis[u,v]>dis[u,v]+dis[v,s],显然矛 盾。2、v不在这条最长路径上,我们在 长路径上选择一个点为po, 则dis[u,v]>dis[u,po]+dis[po,t],那么有dis[s,v]=dis[s,po]+dis[po,u]
+dis[u,v]>dis[s,po]+dis[po,t]=dis[s,t],即dis[s,v]>dis[s,t],矛盾。
也许你想说u本身就在 长路径,或则其它的一些情况,但其实 都能用类似于上面的反证法来证明的。 综上所述,你两次dfs(bfs)就可以求出 长路径的两个端点和路 径长度。
板子看下面:(大家可以先理解一下板子)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> using namespace std; int a,b,c,ans; const int maxn = 1e5+10; int vis[maxn],dis[maxn];//dis数组储存的就是当前点能向一个确定的方向走的最大的距离。vis就是一个标记数组防止重复访问。 vector<pair<int,int> > v[maxn]; //用来存图,可以看成是一个二维数组,因为是有权值的,所以在vector中套用了一个pair int bfs(int x) { memset(vis,0,sizeof(vis));//因为要进行多次bfs,所以每次都要清空一下数组 memset(dis,0,sizeof(dis)); vis[x]=1;//已经访问过的节点标记为1 int point=0;//用来储存当前所能走到的最远的点 queue<int> q;//用来实现bfs的队列 q.push(x); while(!q.empty()) { x=q.front(); q.pop(); if(dis[x]>ans)//如果当前点能走的最大的步数大于ans,ans初始为0,如果大于就更新ans和point的值 { ans=dis[x]; point=x; } pair<int,int> mid; for(int i=0;i<v[x].size();i++)//对v[x]中的每一个元素进行bfs { mid=v[x][i]; if(!vis[mid.first])//没访问过就继续 { vis[mid.first]=1;//标记成已经访问过的 dis[mid.first]=dis[x]+mid.second;//这个点的能走的最大的距离多了一个dis[x] q.push(mid.first);//放进队列以进行bfs } } } return point;//把当前走到的最远的点返回 } int main() { while(cin>>a>>b>>c) { v[a].push_back(make_pair(b,c));//存图 v[b].push_back(make_pair(a,c)); } ans=0;//初始化 int point=bfs(1); ans=0; bfs(point);//第二次以某一端点位起点的bfs cout<<ans<<endl; return 0; }
俩个板子题:
传送门:Cow Marathon POJ - 1985
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> using namespace std; int a,b,c,ans,n,m; const int maxn = 1e5+10; int vis[maxn],dis[maxn]; char s; vector<pair<int,int> > v[maxn]; int bfs(int x) { memset(vis,0,sizeof(vis)); memset(dis,0,sizeof(dis)); vis[x]=1; int point=0; queue<int> q; q.push(x); while(!q.empty()) { x=q.front(); q.pop(); if(dis[x]>ans) { ans=dis[x]; point=x; } pair<int,int> mid; for(int i=0;i<v[x].size();i++) { mid=v[x][i]; if(!vis[mid.first]) { vis[mid.first]=1; dis[mid.first]=dis[x]+mid.second; q.push(mid.first); } } } return point; } int main() { cin>>n>>m; while(m--) { cin>>a>>b>>c>>s; v[a].push_back(make_pair(b,c)); v[b].push_back(make_pair(a,c)); } ans=0; int point=bfs(1); ans=0; bfs(point); cout<<ans<<endl; return 0; }
传送门: Labyrinth POJ - 1383
(似乎没用到板子,但是先理解理解,不着急,反正不难,就是BFS)
大体题意就是找最远的俩个点的距离。里面的细节的题意读者自己理解。
//#include<bits/stdc++.h> #include<algorithm> #include<cmath> #include<cstdio> #include<map> #include<iostream> #include<queue> #include<cstring> using namespace std; typedef long long ll; int xx,yy; char mp[1010][1010]; bool vis[1010][1010]; int dd[4][2]={-1,0,1,0,0,1,0,-1}; struct node { int x,y,step; friend bool operator<(node a,node b) { return a.x>b.x; } }now,next; node bfs(int x,int y) { queue<node> q; now.x=x; now.y=y; now.step=0; q.push(now); vis[x][y]=1; node point; point.step=0; point.x=x; point.y=y; while(!q.empty()) { now=q.front(); if(point.step<now.step) point=now; for(int i=0;i<4;i++) { next.x=now.x+dd[i][0]; next.y=now.y+dd[i][1]; next.step=now.step+1; if(mp[next.x][next.y]=='.'&&vis[next.x][next.y]==0) { vis[next.x][next.y]=1; q.push(next); } } q.pop(); } return point; } int main() { int T; scanf("%d",&T); while(T--) { node q; memset(vis,0,sizeof vis); scanf("%d %d",&yy,&xx); for(int i=0;i<xx;i++) scanf("%s",&mp[i]); for(int i=0;i<xx;i++) { for(int j=0;j<yy;j++) { if(mp[i][j]=='.'&&vis[i][j]==0) q=bfs(i,j); //第一次BFS } } memset(vis,0,sizeof vis); //一定要初始化 q=bfs(q.x,q.y); //第二次BFS printf("Maximum rope length is %d.\n",q.step); } return 0; }
相关题目:
传送门: Roads in the North POJ - 2631
#include<algorithm> #include<cmath> #include<cstdio> #include<map> #include<iostream> #include<queue> #include<cstring> #include<vector> using namespace std; typedef long long ll; const int maxn=100010; int ans; int vis[maxn]; int dis[maxn]; vector<pair<int,int> > v[maxn]; int bfs(int x) { memset(vis,0,sizeof vis); memset(dis,0,sizeof dis); queue<int> q; q.push(x); vis[x]=1; int point =0; while(!q.empty()) { int f=q.front(); q.pop(); if(dis[f]>ans) { ans=dis[f]; point=f; } pair<int,int> t; for(int i=0;i<v[f].size();i++) { t=v[f][i]; if(vis[t.first]==0) { vis[t.first]=1; dis[t.first]=dis[f]+t.second; q.push(t.first); } } } return point; } int main() { int a,b,c; while(~scanf("%d%d%d",&a,&b,&c)) { v[a].push_back(make_pair(b,c)); v[b].push_back(make_pair(a,c)); } ans=0; int point=bfs(1); ans=0; bfs(point); cout<<ans<<endl; return 0; }
传送门:Computer HDU - 2196
#include<iostream> #include<vector> #include<queue> #include<cstring> #include<cstdio> using namespace std; int N,M,X,Y,Z,ans; int dis[40020]; int diss[40020]; bool vis[40020]; vector<pair<int,int> >V[40020]; int bfs(int n){ memset(dis,0,sizeof(dis)); memset(vis,0,sizeof(vis)); queue<int>Q; Q.push(n); vis[n]=1; ans=0; int point,t; while(!Q.empty()){ t=Q.front(); Q.pop(); if(dis[t]>ans){ ans=dis[t]; point=t; } for(int i=0;i<V[t].size();i++){ if(vis[V[t][i].first]==0){ vis[V[t][i].first]=1; dis[V[t][i].first]=dis[t]+V[t][i].second; Q.push(V[t][i].first); } } } return point; } int main(){ while(scanf("%d",&N)!=EOF){ for(int i=0;i<=N;i++) V[i].clear(); for(int i=1;i<N;i++){ scanf("%d%d",&X,&Z); V[i+1].push_back(make_pair(X,Z)); V[X].push_back(make_pair(i+1,Z)); } int point=bfs(bfs(1)); for(int i=1;i<=N;i++){ diss[i]=dis[i]; } bfs(point); for(int i=1;i<=N;i++){ printf("%d\n",max(dis[i],diss[i])); } } return 0; }
传送门:Farthest Nodes in a Tree LightOJ - 1094
#include<algorithm> #include<cmath> #include<cstdio> #include<map> #include<iostream> #include<queue> #include<cstring> #include<vector> using namespace std; const int maxn=100010; int ans; vector<pair<int,int> > v[maxn]; int dis[maxn]; int vis[maxn]; int bfs(int x) { memset(dis,0,sizeof dis); memset(vis,0,sizeof vis); queue<int> q; q.push(x); vis[x]=1; int point=0; while(!q.empty()) { int f=q.front(); q.pop(); if(dis[f]>ans) { ans=dis[f]; point = f; } pair<int,int> t; for(int i=0;i<v[f].size();i++) { t=v[f][i]; if(vis[t.first]==0) { vis[t.first]=1; dis[t.first]=dis[f]+t.second; q.push(t.first); } } } return point; } int main() { int T; cin>>T; int ff=0; while(T--) { int n; int a,b,c; while(~scanf("%d",&n)) { ff++; for(int i=0;i<n-1;i++) { scanf("%d%d%d",&a,&b,&c); v[a].push_back(make_pair(b,c)); v[b].push_back(make_pair(a,c)); } ans=0; int point=bfs(0); ans=0; bfs(point); printf("Case %d: %d\n",ff,ans); for(int i=0;i<n;i++) v[i].clear(); } } return 0; }
传送门:How Many Equations Can You Find HDU - 2266
#include<bits/stdc++.h> using namespace std; string s;int n,ans; void dfs(int x,int now)//x代表的是当前要进行操作的位置,now代表当前得到的值 { if(x==s.size())//如果x已经跟字符串的长度相等说明这一次遍历已经结束了 { if(now==n) ans++;//如果得到的值跟n相等,答案就加一 // cout<<now<<endl; return ; } for(int i=x;i<s.size();i++) { int mid=0; for(int j=x;j<=i;j++) { mid=mid*10+s[j]-'0';//得到运算符左边字符串所代表数的大小 // cout<<mid<<"?"<<now<<endl; } dfs(i+1,now+mid);//去访问下一个位置,并且此时的值加上上面得到的运算符左边字符串所代表的数 if(x) dfs(i+1,now-mid);//减号不能放在最前面,所以要有一个x不为0的判断 } } int main() { while(cin>>s>>n) { ans=0; dfs(0,0);//从s[0]开始,当前值为0 cout<<ans<<endl; } }
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- typedif int mytype[10]的作用
- 10 操作系统
- 电脑开机提示:微软推荐您完成 windows 10 的免费升级准备
- Easy-题目10:217. Contains Duplicate
- React Native商城项目实战10 - 个人中心中间内容设置
- 使用yum安装postgresql 10 dev
- machine learning in action出现ValueError: invalid literal for int() with base 10: 'largeDoses'
- Xcode 10 iOS12 "A valid provisioning profile for this executable was not found
- weblogic10+eclipse 开发ejb3
- Ubuntu10安装apache,mysql,php
- win7系统中IE8.IE9,IE10的关系
- 开源夏令营之项目汇报10(结题报告)
- 剑指offer_面试题10_二进制中1的个数(位运算)
- 每个ios开发者都应该知道Top 10 Swift三方库
- POJ 1382 Labyrinth(数的直径用DFS实现)
- Tersorflow CIFAR-10 训练示例报错及解决方案
- kaldi中改写sre10/v1用timit dataset做说话人识别总结
- [PTA]7-3 逆序的三位数 (10 分)
- Asp.Net Ajax 学习笔记10 JavaScript的原生类型以及Microsoft AJAX Library的相关扩展(下)
- Oracle GoldenGate 10 Essentials (1Z0-539 )