树的直径(10)

树的直径

前面讲的那个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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值