HDU 3848 DFS 树形DP

24 篇文章 0 订阅

            给你一棵树,找出两个叶子之间的最短距离。

            第一种是个纯dfs+稍微的剪枝,从每一个叶子出发,dfs直到找到一个新的叶子,更新最短距离。781ms

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
#define MAXN 10001
#define INF  2147483647
using namespace std;
int n;
vector<int>g[MAXN],w[MAXN];
int angel[MAXN];
int maxx;
bool vis[MAXN];
void dfs(int ori,int cur,int dis)
{
    if(dis>=maxx)   return  ;
    vis[cur]=true;
    if(angel[cur]==1&&cur!=ori)
    {
        maxx=min(maxx,dis);
        return ;
    }
    for(int i=0; i<(int)g[cur].size(); i++)
    {
        int t=g[cur][i];
        if(!vis[t]&&w[cur][i]+dis<maxx)
            dfs(ori,t,w[cur][i]+dis);
    }
}
int  main()
{
//    freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF&&n)
    {
        for(int i=0; i<=n; i++)
            g[i].clear(),w[i].clear(),angel[i]=0;
        maxx=INF;
        for(int i=0; i<n-1; i++)
        {
            int a,b,c;
           scanf("%d%d%d",&a,&b,&c);
            angel[a]++,angel[b]++;
            g[a].push_back(b),w[a].push_back(c);
            g[b].push_back(a),w[b].push_back(c);
        }
        for(int i=1; i<=n; i++)
            if(angel[i]==1)
            {
                memset(vis,false,sizeof(vis));
                dfs(i,i,0);
            }
        printf("%d\n",maxx);
    }
    return 0;
}
              第二种是新接触的树形dp,从任意一个节点出发,dfs回溯,dp[cur][0]表示cur节点到叶子的最短距离,dp[cur][1]表示cur节点到叶子的次短距离。注意dp数组的初始化,(每一个叶子到叶子的最短距离是0)。PS.树形dp,它的原理和名字很像。dp[cur][0]=min{dp[cur][0],dp[u][0]+dis(u,cur)],因为父节点cur的dp值通过子节点来得出,所以通过回溯递归求解每一个节点的dp[][].

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#define MAXN 10010
#define INF 20000000
using namespace std;
vector<int>g[MAXN],w[MAXN];
int n,dp[MAXN][2],degree[MAXN];
bool  vis[MAXN];
int maxx;
void dfs(int cur)
{
    vis[cur]=true;
    for(int i=0; i<(int)g[cur].size(); i++)
    {
        int t=g[cur][i];
        if(!vis[t])
        {
            dfs(t);
            if(w[cur][i]+dp[t][0]<dp[cur][0])
            {
                dp[cur][1]=dp[cur][0];
                dp[cur][0]=w[cur][i]+dp[t][0];
            }
            else if(w[cur][i]+dp[t][0]<dp[cur][1])
                dp[cur][1]=w[cur][i]+dp[t][0];
//            printf("cur:%d %d %d\n",cur,dp[cur][0],dp[cur][1]);
        }
    }
    maxx=min(maxx,dp[cur][0]+dp[cur][1]);
}
int main()
{
    freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF&&n)
    {
        for(int i=0; i<=n; i++)
            g[i].clear(),w[i].clear(),degree[i]=0;
        for(int i=1; i<n; i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            degree[a]++,degree[b]++;
            g[a].push_back(b),g[b].push_back(a);
            w[a].push_back(c),w[b].push_back(c);
        }
        for(int i=1; i<=n; i++)
        {
            dp[i][0]=dp[i][1]=INF;
            if(degree[i]==1)
                dp[i][0]=0;
        }
        memset(vis,false,sizeof(vis));
        maxx=INF;
        dfs(1);
        printf("%d\n",maxx);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值