The Longest Path 两种解法

View Code
/* 
【题目来源】
http://soj.me/show_problem.php?pid=1003&cid=567
【题目分析】
给定一些边确定一个图,即给定一些点之间的连通情况,保证给定的图没有回路,要求输出该图存在的最长路径。  
【思路分析】
. 根据给定信息构造图,用邻接表表示。(邻接矩阵明显很麻烦且效率不高) 
. 将每一个顶点看成是树根,求出树的高度。
. 得到一系列树的高度,最大的那个就是图中存在的最长路径。嗯对的。  
【陷阱分析】
.不应该被数据蒙骗,比如只给两条边但顶点不一定是1,2,3而有可能是1,99,100之类,所以数组开最大(题目范围1-100,所以开个105绝对够了) 
【小小感受】
用vector构造邻接表确实比较方便~ 学习了 
*/
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

#define Max 105
int main()
{
    int m;
    
    cin >> m;
    
    while (m--)
    {
        int n;
        
        cin >> n;
        
        vector<int> v[Max];//用vector构造邻接表 
        
        bool visit[Max];//记录该点是否已经被访问过 
        
        //构造邻接表 
        int temp1, temp2;
        for (int i = 0; i < n; ++i)
        {
            cin >> temp1 >> temp2;
            
            v[temp1].push_back(temp2);//无向图 temp1通temp2 
            
            v[temp2].push_back(temp1);//无向图 temp2通temp1
        }
        int ans = 0;
        
        //广搜咯~~~~ 求树的高度 
        for (int i = 1, j = 1; j < 3; j++)
        {
            int height[Max] = {0};
            
            memset(visit, 0, sizeof(visit));
            
            queue<int> q;
            
            q.push(i);
            
            visit[i] = 1;
            
            while (!q.empty())
            {   
                int current = q.front();
                
                q.pop();
                
                for (int j = 0; j < v[current].size(); ++j)
                    if (!visit[v[current][j]])
                    {
                        q.push(v[current][j]);
                        
                        height[v[current][j]] = height[current]+1;//current所连接的节点的高度要比current多1 (其实这里理解成深度会更好) 
                        
                        visit[v[current][j]] = 1;
                    }
                i = current;
            }
            int max = *max_element(height, height+Max);//该点作为树根时树的高度 
            
            if (ans < max) ans = max;//更新最大值 
        }
        
        cout << ans << endl;
    }
}                                 
View Code
/*
受乔帮主提点,这道题果然有更简单的做法 
【思路分析】
通俗来讲,把给定的图看成是一串珠子,随便拿起其中一颗,吊起来,那么再拿起此时这串珠子最下面的那颗,再吊起来
ok,那么这时这串珠子的高度就是这一整个图存在的最长路径。
好神奇。
我自己粗略的证明 :
随便拿起的这颗记为A,最底下那颗记为B。
拿起A:
此时B一定是最长路径里面的一点。 
注意,此时A到B之间必定至少有2点是属于最长路径的,即除了B外还至少有一点C,并且这一点C在 A 到 A和B的中间。(若有多点,则C取最高的那一点) 
(为什么C不能在B 到 A和B的中间呢,反证一下即可)
离C最远的点现在必定是B 
拿起B:
现在离C最远的必定是最低的那点D,所以综合C在最长路径上,C离B最远,可得出BD为最长路径。  
【小小疑问】 
既然开始时是随机选一点,我还是不知道为什么选1就对,选temp2就不对。 
*/
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

#define Max 105
int main()
{
    int m;
    
    cin >> m;
    
    while (m--)
    {
        int n;
        
        cin >> n;
        
        vector<int> v[Max];//用vector构造邻接表 
        
        bool visit[Max];//记录该点是否已经被访问过 
        
        //构造邻接表 
        int temp1, temp2;
        for (int i = 0; i < n; ++i)
        {
            cin >> temp1 >> temp2;
            
            v[temp1].push_back(temp2);//无向图 temp1通temp2 
            
            v[temp2].push_back(temp1);//无向图 temp2通temp1
        }
        int ans = 0;
        
        //循环2次就行啦~~~ 
        for (int i = 1, j = 1; j < 3; j++)
        {
            int height[Max] = {0};
            
            memset(visit, 0, sizeof(visit));
            
            queue<int> q;
            
            q.push(i);
            
            visit[i] = 1;
            
            while (!q.empty())
            {   
                int current = q.front();
                
                q.pop();
                
                for (int j = 0; j < v[current].size(); ++j)
                    if (!visit[v[current][j]])
                    {
                        q.push(v[current][j]);
                        
                        height[v[current][j]] = height[current]+1;//current所连接的节点的高度要比current多1 (其实这里理解成深度会更好) 
                        
                        visit[v[current][j]] = 1;
                    }
                i = current;
            }
            int max = *max_element(height, height+Max);//该点作为树根时树的高度 
            
            if (ans < max) ans = max;//更新最大值 
        }
        
        cout << ans << endl;
    }
}

 

posted @ 2012-12-15 15:52  Norcy  阅读(685)  评论(0编辑  收藏  举报