poj 3763 Tour in Wonder Land 树形dp ★★

原创 2016年08月29日 00:26:09

题目


题意:
给出一棵树(n<=1e5),求最少添加多少条边,使得能得到一条遍历所有点的哈密顿路径。(原题说是从点1出发,遍历每个点一遍,并且回到点1)


这个题目又给我上了一课…
训练赛的时候想了2个小时,最后放弃了… 感觉自己想到了其中一部分,还差一部分。
首先这个题目要考虑的是一个环,容易想到先考虑链,最后加1。这个基本想到了。
之后基于链考虑就有两种状态,一种是从根结点出发,一种是非根结点出发。这两个状态确实都想到了,最后在这里纠结了半天,最后弃疗了,因为没有处理好这个两个状态之间的关系,另辟蹊径地去想状态转移方程,最后炸了。之前一直在考虑,从非根节点出发的结果应该是从根结点出发的结果-1或者不减,然后分情况想了半天,然后对于单一子结点的情况和多个子结点的情况去分析把人搞晕了,最后实在不好转移…

dp[x][0]表示从根结点出发,整个路径形成一条链面,所需添加的最小边数。

dp[x][1]表示从非根节点出发,整个路径形成一条链面,所需添加的最小边数。

dp[x][0]=min{dp[u][0]+v is a son of xv!=udp[v][1]+son(x)1}

dp[x][1]=min{dp[u][0]+dp[v][0]+wu,wvdp[w][1]+son(x)2}
(为什么要这样,因为根结点x必须遍历,那一定是要到某个叶子结点,因为不从x出发,所以必须是从某个叶子结点到另一个叶子结点。还有一点就是叶子结点到根到叶子结点可以想象为根到两个叶子结点,这个用dp[][0]表示是等价的)
如果没有两个子结点,令dp[x][1]=dp[x][0]
其实你可以发现dp[x][1]<=dp[x][0]

最后考虑形成一个环,答案=dp[x][1]+1
可能会有疑问:那么出发点可能不是从1出发?
因为行成的是一个环,所以出发点就无所谓了,即使不是从1出发,那么现在就从1出发,还是走刚才的路线,所需添加的边不变。这就是由链到环的变化。


#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define mes(a,x,s)  memset(a,x,(s)*sizeof a[0])
#define mem(a,x)  memset(a,x,sizeof a)
#define ysk(x)  (1<<(x))
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const int maxn= 100000   ;
int n;
vector<int >G[maxn+4];
int dp[maxn+4][2];

void update(int &x,int val)  {   if(x<0||val<x) x=val;   }
void dfs(int x,int fa)
{
    int siz=G[x].size(),son=0;
    if(siz==1)  { dp[x][0]=dp[x][1]=0;return; }
    int ret=0;dp[x][0]=dp[x][1]=-1;
    for0(i,siz) if(G[x][i]!=fa)
    {
        int y=G[x][i];dfs(y,x);son++;
        ret+=dp[y][1];
    }//update dp[x][0]
    for0(i,siz)  if(G[x][i]!=fa)
    {
        int y=G[x][i];
        update(dp[x][0],  ret-dp[y][1]+dp[y][0]+son-1  );
    }//then update dp[x][1]
    for0(i,siz) if(G[x][i]!=fa)
    {   int y0=G[x][i];
        for(int j=i+1;j<siz;j++)   if(G[x][j]!=fa)
        {   int y1=G[x][j];
            update(dp[x][1], ret-dp[y0][1]-dp[y1][1]+dp[y0][0]+dp[y1][0]+son-2        );
        }
    }
    if(dp[x][1]==-1)  dp[x][1]=dp[x][0];
}
int main()
{
   int x,y;
   while(~scanf("%d",&n))
   {
       for1(i,n)  G[i].clear();
       for0(i,n-1)
       {
           scanf("%d%d",&x,&y);
           G[x].push_back(y);G[y].push_back(x);
       }
       dfs(1,-1);
       printf("%d\n",dp[1][1]+1);
   }
   return 0;
}


这个题有个重要的考虑就是对于结点x,子节点y为根的子树内所有结点的遍历应该是连续的。

还有就是dp[x][1]小于等于dp[x][0]。

相关文章推荐

HDU 4044 GeoDefense(树形DP+分组背包)★

题目大意:给定n个节点组成的树,1为敌方基地,叶子结点为我方结点。我们可以在每个结点安放炮台,至多一炮,然后就可以打炮,每个结点有ki种炮,每种炮有一个花费和一个能量(能量对应着打掉敌人多少hp)。敌...
  • Ezereal
  • Ezereal
  • 2016年08月08日 09:19
  • 546

hdu 5378 Leader in Tree Land 2015多校联合训练赛 树形dp

Leader in Tree Land Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Othe...

CodeForces 631E Product Sum(斜率优化DP+二分|三分) ★

题意:给出n个数,现在可以移动一个数的位置,现在要使和sigma(ai*i)最大,询问这个最大和。 思路:将一个数向左移动和向右移动是一样的,现在考虑向左移动。 先预处理出前缀和,将一个数向左移动后,...
  • Ezereal
  • Ezereal
  • 2016年09月07日 16:21
  • 666

ZOJ 3329 One Person Game(概率DP,求期望)★

/*题意: 有三个骰子,分别有k1,k2,k3个面。 每次掷骰子,如果三个面分别为a,b,c则分数置0,否则加上三个骰子的分数之和。 当分数大于n时结束。求游戏的期望步数。初始分数为0 分析: 假...
  • Ezereal
  • Ezereal
  • 2016年07月31日 16:17
  • 218

★ POJ 2516 最小费用最大流(分开计算,K次费用流)

题意:给你m个供货源,n个店,k种商品,

★ poj 2125 二分图的最小点权覆盖+输出解

Destroying The Graph Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 71...

POJ 1308 Is It A Tree? 基础并查集★

题目大意就是判断是否为一棵树 注意:0 0空树也是树 然后自己指向自己也是不可以的 #include #include #include #include #include #include...

poj 3028 Shoot-out 概率dp ★★

题意:n个枪手站在一起,轮流射击,每次只能射一发,且只能射自己以外的人,命中即死。每个人每次射击都有一个命中率。游戏到剩下最后一个人存活结束。每个人每次射击会用最优决策(决策后,自己存活率最高),如果...

HDU 5378 Leader in Tree Land(树形背包+组合数学)

题意:把1到n划分到n个结点的树中,子树的领导是这个子树中权值最大的点。求n个结点的树中,领导为k个的情况数。 思路:树形背包。用dp[i][j]表示以i为根的子树中领导为j个的情况数。 首先用siz...

**HDU 5378 - Leader in Tree Land(概率DP)

题目: http://acm.hdu.edu.cn/showproblem.php?pid=5378 题意: 给你一棵树,有n个人,标号分别是1~n,每个节点放一个人。对于一棵子树来说,标号...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:poj 3763 Tour in Wonder Land 树形dp ★★
举报原因:
原因补充:

(最多只允许输入30个字)