POJ 树的直径和重心

树的直径:(无根)树上最长两点间的最长路径,两次dfs即可,第一次dfs任选一点u,找到距离它最远的点s,再从点s进行一次dfs,找到距离s最远的点t,则s-t之间的路径就是树的直径。证明: <http://www.cnblogs.com/wuyiqi/archive/2012/04/08/2437424.html>

poj2631 树的直径裸题

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<iostream>
#include<vector>
typedef long long ll;
using namespace std;
const int maxn=10005;
ll d[maxn];
struct KSD
{
    int v,len,next;
}g[maxn];
int vis[maxn];
int head[maxn],cnt;
void add(int u,int v,int len){
    g[++cnt].v=v;
    g[cnt].next=head[u];
    g[cnt].len=len;
    head[u]=cnt;
}
void dfs(int x)
{
    vis[x]=1;
    int i,v;
    for(i=head[x];i;i=g[i].next)
    {
        v=g[i].v;
        if(vis[v])continue;
        d[v]+=d[x]+g[i].len;
        dfs(v);
    }
    return ;
}
int main(){
    int a,b,c;int n=0;
    while(scanf("%d%d%d",&a,&b,&c)!=EOF){

        n=max(a,max(b,n));
        add(a,b,c);
        add(b,a,c);

    }
        d[1]=0;
        dfs(1);
        int m;
        ll s=0;
        for(int i=1;i<=n;i++){
            vis[i]=0;
            if(d[i]>s){
                m=i;
                s=d[i];
            }
            d[i]=0;
        }
        dfs(m);
        ll ans=0;
        for(int i=1;i<=n;i++)
            ans=max(ans,d[i]);
    printf("%lld\n",ans);
}

poj1985 Cow Marathon 求树的直径裸题

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=200005;
int n,m;
struct P{
    int v,len,next;
}g[maxn];

int head[maxn],d[maxn],vis[maxn];
int cnt=0;
void add(int u,int v,int len){
    g[++cnt].v=v;
    g[cnt].next=head[u];
    g[cnt].len=len;
    head[u]=cnt;
}
void dfs(int x)
{
    vis[x]=1;
    int i,v;
    for(i=head[x];i;i=g[i].next)
    {
        v=g[i].v;
        if(vis[v])continue;
        d[v]+=d[x]+g[i].len;
        dfs(v);
    }
    return ;
}
int main(){
    scanf("%d%d",&n,&m);
    int sum=0;
    for(int i=1;i<=n-1;i++){
        int x,y,z;
        char c;
        scanf("%d%d%d %c",&x,&y,&z,&c);
      //  cout<<c<<endl;
        add(x,y,z);
        add(y,x,z);
       // sum+=z;
    }
   // sum=sum*2;
        d[1]=0;
        dfs(1);
        int m;
        int s=0;
        for(int i=1;i<=n;i++){
            vis[i]=0;
            if(d[i]>s){
                m=i;
                s=d[i];
            }
            d[i]=0;
        }
        dfs(m);
        int ans=0;
        for(int i=1;i<=n;i++)
            ans=max(ans,d[i]);
      //  cout<<sum<<" "<<ans<<endl;
        printf("%d\n",ans);
}

poj3310 Caterpillar

给你一张无向图,问你这张图是否是一个Caterpillar,Caterpillar必须满足是一个连通图,无环,切存在一条路径,使图中所有的点距离该路径上点的最小距离为1或0

易知改图是一棵树,首先并查集判断是否联通,先找到直径,再判断所有点距离直径距离

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=605;
int fa[maxn],head[maxn],d[maxn],ans[maxn],vis[maxn];
struct P{
    int v,len,next;
}g[maxn*2];
int  mp[maxn][maxn];
int fi(int x){
    if(fa[x]==x)
        return x;
    return fa[x]=fi(fa[x]);
}
int cnt=0;
void add(int u,int v){
    g[++cnt].v=v;
    g[cnt].next=head[u];
    head[u]=cnt;
}
void dfs(int x)
{
    vis[x]=1;
    int i,v;
    for(i=head[x];i;i=g[i].next)
    {
        v=g[i].v;
        if(vis[v])continue;
        d[v]+=d[x]+1;
        dfs(v);
    }
    return ;
}
int n,m,p,q,k=0;
bool DFS(int z){
    if(z==q){
        ans[z]=1;
        return true;
    }
    vis[z]=1;
    for(int i=head[z];i;i=g[i].next){
        int v=g[i].v;
        if(vis[v])
            continue;
        if(DFS(v)){
            ans[v]=1;
            return true;
        }
    }
    return false;
}
int main(){
    int cas=0;
    while(scanf("%d",&n)&&n!=0){
        for(int i=1;i<=n;i++){
            d[i]=vis[i]=ans[i]=head[i]=0;
            fa[i]=i;
            for(int j=1;j<=n;j++)
                mp[i][j]=0;
        }
        scanf("%d",&m);
        bool f=1;
        if(m!=n-1)
            f=0;
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            mp[x][y]=mp[y][x]=1;
            x=fi(x);y=fi(y);
            if(x==y)
                f=0;
            fa[x]=y;
            add(x,y);
            add(y,x);
        }
        for(int i=1;i<=n;i++)
        if(fi(i)!=fi(1)){
            f=0;
            break;
        }
        if(f==0){
            printf("Graph %d is not a caterpillar.\n",++cas);
            continue;
        }
        dfs(1);
        int s=0;
        for(int i=1;i<=n;i++){
            vis[i]=0;
            if(d[i]>s){
                p=i;
                s=d[i];
            }
            d[i]=0;
        }

        dfs(p);
        s=0;
        for(int i=1;i<=n;i++){
            vis[i]=0;
            if(d[i]>s){
                q=i;
                s=d[i];
            }
            d[i]=0;
        }

        DFS(p);
        for(int i=1;i<=n;i++){
            int j=0;
            if(ans[i]==0){
                for(j=1;j<=n;j++)
                if(ans[j]==1){
                    if(mp[i][j]==1)
                        break;
                }
                if(j>n){
                    f=0;
                    break;
                }
            }

        }
        if(f==0){
              printf("Graph %d is not a caterpillar.\n",++cas);
        }
        else   printf("Graph %d is a caterpillar.\n",++cas);

    }
}

poj1849 Two

大雪将城镇的街道覆盖了,两辆铲雪机从同一城市出发,要求将所有街道得雪都铲完,任意一辆铲雪机可以铲任意一条街道,最后两辆车可以停在任意一处,问两辆车的最少运动长度

有些道路可以经过一次,但有些街道需要经过两次,那么即找到一条最长的距离,车子只要走一趟,易知这条路径即为直径,故答案为所有边的长度*2-直径

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=200005;
int n,m;
struct P{
    int v,len,next;
}g[maxn];

int head[maxn],d[maxn],vis[maxn];
int cnt=0;
void add(int u,int v,int len){
    g[++cnt].v=v;
    g[cnt].next=head[u];
    g[cnt].len=len;
    head[u]=cnt;
}
void dfs(int x)
{
    vis[x]=1;
    int i,v;
    for(i=head[x];i;i=g[i].next)
    {
        v=g[i].v;
        if(vis[v])continue;
        d[v]+=d[x]+g[i].len;
        dfs(v);
    }
    return ;
}
int main(){
    scanf("%d%d",&n,&m);
    int sum=0;
    for(int i=1;i<=n-1;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);
        sum+=z;
    }
    sum=sum*2;
        d[1]=0;
        dfs(1);
        int m;
        int s=0;
        for(int i=1;i<=n;i++){
            vis[i]=0;
            if(d[i]>s){
                m=i;
                s=d[i];
            }
            d[i]=0;
        }
        dfs(m);
        int ans=0;
        for(int i=1;i<=n;i++)
            ans=max(ans,d[i]);
      //  cout<<sum<<" "<<ans<<endl;
        printf("%d\n",sum-ans);
}

poj3099 Go Go Gorelians

给你一张图,已知两两之间的距离为1,问你找出使距离某个点最远距离最小的点,即找到直径,若直径上的点为奇数,则为中间的,若为偶数,则为中间两个,注意输入给的距离是让我们建树的

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

const int maxn=10005;
int vis[maxn],head[maxn],cnt,v0[maxn];
struct P{
    int v,next;
  //  double len;
}g[maxn];
struct Q{
    int i,x,y,z;
}p[maxn];
int d[maxn],ans[maxn];
//int sum=0;
void add(int u,int v){
    g[++cnt].v=v;
   // g[cnt].len=len;
    g[cnt].next=head[u];
    head[u]=cnt;
}
int ma;  int n;

void dfs(int x)
{
    vis[x]=1;
    int i,v;
    for(i=head[x];i;i=g[i].next)
    {
        v=g[i].v;
        if(vis[v])continue;
        d[v]+=d[x]+1;
        dfs(v);
    }
    return ;
}
int q;
int l;
bool DFS(int z){
    if(z==q){
        return true;
    }
    vis[z]=1;
    for(int i=head[z];i;i=g[i].next){
        int v=g[i].v;
        if(vis[v])
            continue;
        if(DFS(v)){
            ans[++l]=v;
            return true;
        }
    }
    return false;
}
int main(){

    int c=0;
    while(scanf("%d",&n)&&n!=0){
        l=0;
        ma=1e7;
        for(int i=1;i<=1000;i++)
          vis[i]=head[i]=ans[i]=d[i]=0;
        c=0;
        cnt=0;
        for(int i=1;i<=n;i++){
            scanf("%d%d%d%d",&p[i].i,&p[i].x,&p[i].y,&p[i].z);
            v0[++c]=p[i].i;
        }
        for(int i=2;i<=n;i++){
            int s=1e9;
            int t;
            for(int j=1;j<i;j++){
                int o=(p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y)+(p[i].z-p[j].z)*(p[i].z-p[j].z);
                if(o<s){
                    s=o;
                    t=p[j].i;
                }
            }
            add(t,p[i].i);
            add(p[i].i,t);
       
        }
        dfs(v0[1]);
        int c;
        int s=0;
        for(int i=1;i<=n;i++){
            int k=v0[i];
            vis[k]=0;
            if(d[k]>s){
                c=k;
                s=d[k];
            }
            d[k]=0;
        }

        dfs(c);
        s=0;
        for(int i=1;i<=n;i++){
            int k=v0[i];
            vis[k]=0;
            if(d[k]>s){
                q=k;
                s=d[k];
            }
            d[k]=0;
        }

        DFS(c);
       ans[++l]=c;
     if(l%2==0){
        cout<<min(ans[l/2+1],ans[l/2])<<" "<<max(ans[l/2+1],ans[l/2])<<endl;
     }
     else printf("%d\n",ans[l/2+1]);
    }
}

  

树的重心:如果存在某个节点,其所有子树中最大节点的子树最小,则该节点为树的重心;任选一个点作为根,进行dfs,记录某个节点的子节点数,则满足max(n-son[u]-1,sou[v])取最小的节点u即为树的重心(v为u的子节点);

poj3107 Goldfather

树的重心裸题

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100005;
int cnt,d[maxn],vis[maxn],head[maxn],ans[maxn];
struct P{
    int v,next;
}g[maxn];
void add(int u,int v){
    g[++cnt].v=v;
    g[cnt].next=head[u];
    head[u]=cnt;
}
int ma=1e9;
int n;
void dfs(int u){
    int sum=0;
    d[u]=1;
    vis[u]=1;
    for(int i=head[u];i;i=g[i].next){
        int v=g[i].v;
        if(vis[v])
            continue;
        dfs(v);
        d[u]+=d[v];
        if(d[v]>=ans[u])
            ans[u]=d[v];
    }
    if(n-d[u]>ans[u])
    ans[u]=n-d[u];
    if(ma>ans[u])
    ma=ans[u];
}
int main(){
        cnt=0;

        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            head[i]=d[i]=vis[i]=0;
        }
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        dfs(1);
        for(int i=1;i<=n;i++){
            if(ans[i]==ma)
            printf("%d ",i);
        }
        printf("\n");
}

poj1655 Banlancing Act

求树的重心,输出字典序最小的

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100005;
int cnt,d[maxn],vis[maxn],head[maxn];
struct P{
    int v,next;
}g[maxn];
void add(int u,int v){
    g[++cnt].v=v;
    g[cnt].next=head[u];
    head[u]=cnt;
}
int ans1,ans2;
int n;
void dfs(int u){
    int sum=0;
    d[u]=1;
    vis[u]=1;
    for(int i=head[u];i;i=g[i].next){
        int v=g[i].v;
        if(vis[v])
            continue;
        dfs(v);
        d[u]+=d[v];
        sum=max(sum,d[v]);
    }
    sum=max(sum,n-d[u]);
    if((sum<ans2)||(sum==ans2&&u<ans1)){
        ans1=u;
        ans2=sum;
    }

}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        cnt=0;
        ans1=1e8;
        ans2=1e8;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            head[i]=d[i]=vis[i]=0;
        }
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        dfs(1);
        printf("%d %d\n",ans1,ans2);
    }
}

  

猜你喜欢

转载自www.cnblogs.com/dlutjwh/p/10987787.html