POJ 1985 Cow Marathon && POJ 1849 Two(树的直径)

树的直径:树上的最长简单路径。

求解的方法是bfs或者dfs。先找任意一点,bfs或者dfs找出离他最远的那个点,那么这个点一定是该树直径的一个端点,记录下该端点,继续bfs或者dfs出来离他最远的一个点,那么这两个点就是他的直径的短点,距离就是路径长度。具体证明见http://www.cnblogs.com/wuyiqi/archive/2012/04/08/2437424.html 其实这个自己画画图也能理解。

POJ 1985

题意:直接让求最长路径。

可以用dfs也可以用bfs

bfs代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 200000;
int tot, head[maxn];
struct Edge {
    int to, next, w;
}edge[maxn];
bool vis[maxn];
void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int w)
{
    edge[tot].to = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}
int maxx, pos;
void bfs(int p)//从p开始找到离他最远的那个点,距离保存在maxx当中 
{
    maxx = -1;
    memset(vis, false, sizeof(vis));
    queue<pii> Q;
    vis[p] = true;
    pii cur, nex;
    cur.first = p; cur.second = 0;//pair的first表示节点编号,second表示权值 
    Q.push(cur);
    while (!Q.empty())
    {
        cur = Q.front();
        Q.pop();
        for (int i = head[cur.first]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if (vis[v]) continue;
            vis[v] = true;
            nex.first = v; nex.second = cur.second + edge[i].w;
            if (maxx < nex.second)//如果找到最大的就替换 
            {
                maxx = nex.second;
                pos = v;
            }
            Q.push(nex);
        }
    }
}
int main()
{
    int n, m;
    while (~scanf("%d %d", &n, &m))
    {
        init();
        int u, v, w;
        for (int i = 0; i < m; i++)
        {
            scanf("%d %d %d %*s", &u, &v, &w);
            addedge(u, v, w);
            addedge(v, u, w);
        }
        bfs(1);
        bfs(pos);
        printf("%d
", maxx);
    }    
    return 0;
} 
View Code

dfs代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 200000;
int tot, head[maxn];
struct Edge {
    int to, next, w;
}edge[maxn];
bool vis[maxn];
void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int w)
{
    edge[tot].to = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}
int maxx, pos;
void dfs(int p, int fa, int w)
{
    for (int i = head[p]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if (v == fa || vis[v]) continue;
        vis[v] = true;
        if (w + edge[i].w > maxx)
        {
            maxx = w + edge[i].w;
            pos = v;
        }
        dfs(v, p, w + edge[i].w);
        vis[v] = false;
    }
} 
void solve()
{
    memset(vis, false, sizeof(vis));
    maxx = -1;
    dfs(1, 0, 0);
    maxx = -1;
    dfs(pos, 0, 0);
    printf("%d
", maxx);
}
int main()
{
    int n, m;
    while (~scanf("%d %d", &n, &m))
    {
        init();
        int u, v, w;
        for (int i = 0; i < m; i++)
        {
            scanf("%d %d %d %*s", &u, &v, &w);
            addedge(u, v, w);
            addedge(v, u, w);
        }
        solve();
    }    
    return 0;
} 
View Code

POJ 1849

题意: 给出一棵树,两个人从给定的点s开始走,走完这棵树最少走的长度。

思路:如果要回到当初的点,根据树的性质,那么一定是将这棵树走了两遍,但是题目要求可以停在任何位置,所以走不到两边,有些边走了一遍,求最小花费,那么一定是最长的那条路径走了一遍,其他都是两遍,这样才是最小花费。仔细想想其实从哪个点开始走并不影响最后的结果。因为不管哪个点肯定都要走完。要使两个人走的简单路径最长,那么这两个人走的路径就是树的最长路径了。所以答案就是:两倍的所有路径权值之和减去树的直径

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 220000;
int tot, head[maxn];
struct Edge {
    int to, next, w;
}edge[maxn];
bool vis[maxn];
void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int w)
{
    edge[tot].to = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}
int maxx, pos;
void bfs(int p)
{
    maxx = -1;
    memset(vis, false, sizeof(vis));
    queue<pii> Q;
    pii cur, nex;
    cur.first = p; cur.second = 0;
    vis[p] = true;
    Q.push(cur);
    while (!Q.empty())
    {
        cur = Q.front();
        Q.pop();
        for (int i = head[cur.first]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if (vis[v]) continue;
            vis[v] = true;
            nex.first = v; nex.second = cur.second + edge[i].w;
            if (nex.second > maxx)
            {
                maxx = nex.second;
                pos = v;
            }
            Q.push(nex);
        }
    }
}
int main()
{
    int n, s;
    while (~scanf("%d %d", &n, &s))
    {
        init();
        int u, v, w, ans = 0;
        for (int i = 1; i < n; i++)
        {
            scanf("%d %d %d", &u, &v, &w);
            addedge(u, v, w);
            addedge(v, u, w);
            ans += w * 2;
        }
        bfs(s);
        bfs(pos);
        printf("%d
", ans - maxx);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Howe-Young/p/4778851.html