您的位置:首页 > 其它

树的直径(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;
}
}
  • 点赞
  • 收藏
  • 分享
  • 文章举报
〆℡小短腿走快点ゝ 发布了30 篇原创文章 · 获赞 1 · 访问量 1418 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: