樹的直徑
前面講的那個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;
}
}