POJ or HDU以前做过的题目整理(树形DP)

POJ 1849 Two

题目链接:http://poj.org/problem?id=1849

题意:给你一棵树,每条边都有权值,给你两个人去遍历这棵树,问将这棵树遍历完的最小代价是多少,给定两个人的起点,两个人不一定要回到起点。

思路:但是如果不回来,则所走路径中有一条简单路径是可以只走一遍的,派出了两个点去遍历,也就是说有两条简单路径是可以直走一边的,我们要使这两条简单路径的总和尽可能的长,就转换为了树的最长路径问题了,所以答案就为总的边权和的两倍减去树的最长路。

otherwords:求出所有的边的权值和2倍,然后减去树的直径。

代码:

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <string>
using namespace std;
typedef long long LL;

const int N = 100005;
vector<pair<int,int> > g[N];
int vis[N],dist[N];
int bfs(int &s)
{
    int mac = 0;
    memset(vis,0,sizeof(vis));
    queue<int> que;
    que.push(s);
    dist[s] = 0;
    vis[s] = 1;
    while(!que.empty())
    {
        int now = que.front();
        que.pop();
        for(int i=0; i<g[now].size(); i++)
        {
            int v = g[now][i].first;
            int w = g[now][i].second;
            if(vis[v])
                continue;
            dist[v] = dist[now] + w;
            if(dist[v] > mac)
                mac = dist[v],s = v;
            vis[v] = 1;
            que.push(v);
        }
    }
    return mac;
}
int main()
{
    //freopen("in.txt","r",stdin);
    int n,s,a,b,w;
    while(scanf("%d%d",&n,&s)!=EOF)
    {
        int sum = 0;
        for(int i=0; i<n-1; i++)
        {
            scanf("%d%d%d",&a,&b,&w);
            sum += 2 * w;
            g[a].push_back(make_pair(b,w));
            g[b].push_back(make_pair(a,w));
        }
        bfs(s);
        int mac = bfs(s);
        printf("%d\n",sum - mac);
    }
    return 0;
}
View Code

 

posted @ 2015-03-15 10:34  Doli  阅读(258)  评论(0)    收藏  举报