• HDU4514 湫湫系列故事——设计风景线 ——树的直径/树形dp+判环


    中文题面,给出一个图,问能不能成环,如果可以就输出YES。否则输出该树的直径。

    这里的判环我们用路径压缩的并查集就能很快的判断出来,可以在输入的同时进行判断。这题重点就是求树的直径。

    树直径的性质可以参考https://blog.csdn.net/pi9nc/article/details/12394117   实现在代码求法上的就是:

          

    假设 s-t这条路径为树的直径,或者称为树上的最长路

    从任意一点u出发搜到的最远的点一定是s、t中的一点,然后在从这个最远点开始搜,就可以搜到另一个最长路的端点,即用两遍广搜就可以找出树的最长路

    搜的时候要注意  ,什么时候该清空什么数组  在代码中有一定的解释

    #include<iostream>
    #include<vector>
    #include<queue>
    #include<string.h>
    using namespace std;
    #define p pair<int,int>
    vector<p> a[100050];
    bool pd[100050],pdd[100050]; //pd数组判断该点有没有遍历到  pdd数组是保证每一个点都要被遍历过 
    int dp[100050]; //dp值为以改点为起点最长路径,在第一次找端点遍历后要清零 
    int ans,mark,anss;//annss为最终答案,mark用来标记第一次bfs找到的树的直径的端点 
    int bfs(int u)
    {
        ans=0;
        memset(pd,false,sizeof(pd));
        memset(dp,false,sizeof(dp));
        pd[u]=pdd[u]=1;
        queue<int> q;
        q.push(u);
        while(q.size()!=0)
        {
            int t=q.front();
            q.pop();
            for(int i=0;i<a[t].size();i++)
            {
                int v=a[t][i].first;
                if(pd[v]) continue;
                int w=a[t][i].second;
                //cout<<"w="<<w<<endl;
                
                pd[v]=pdd[v]=1;
                dp[v]=dp[t]+w;
                if(ans<dp[v])
                {
                    ans=dp[v];
                    mark=v;
                }
                q.push(v);
            }
        }
        return mark;
    }
    int f[100010];//压缩路径并查集
    int die(int u)  
    {
        if(f[u]==u) return u;
        f[u]=die(f[u]);
        return f[u];
    }
    int main()
    {
        int i,j,k,l,x,y,n,huan,m;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            memset(pdd,false,sizeof(pdd));
            huan=0;anss=0;
            int u,v,c;
            for(i=1;i<=n;i++) f[i]=i,a[i].clear();//初始化father数组,同时清空上个输入留下的关系路径 
            for(i=1;i<=m;i++)
            {
                scanf("%d%d%d",&u,&v,&c);
                x=die(u);y=die(v);
                if(x!=y) f[x]=y;
                else huan=1;  //代表能成环 
                a[u].push_back(p(v,c));
                a[v].push_back(p(u,c));
            }
            if(huan)
            {
                printf("YES
    ");
                continue;
            }
            for(i=1;i<=n;i++) //循环保证所有的点都被遍历过 
            {
                if(!pdd[i])
                {
                    int sb=bfs(i);
                //    cout<<ans<<endl;
                //    cout<<"sb="<<sb<<endl;
                    int hp=bfs(sb);
                //    cout<<ans<<endl;
                    anss=max(anss,dp[hp]);
                }
            }
            
            printf("%d
    ",anss);
            
        }
        
    }
  • 相关阅读:
    动软代码生成器 修改配置
    显示转换explicit和隐式转换implicit
    Memcache学习整理
    SQL2008-分页显示3种方法
    SQL2008-表对表直接复制数据
    SQL2008-删除时间字段重复的方法
    SQL2008-中不想插入从复记录
    SQL2008-c:PROGRA~1COMMON~1SystemOLEDB~1oledb32.dll出错找不到指定的模块
    ACCESS-如何多数据库查询(跨库查询)
    ACCESS-字符函数
  • 原文地址:https://www.cnblogs.com/wsblm/p/10720094.html
Copyright © 2020-2023  润新知