一道树状DP的题目 =.=
题目链接 (用的Vjudge上的)
题意为给予一颗树,求最少加多少条边可以使得每个节点都属于唯一一个环。
问题可以转换为将一颗树分割成N条链,(因为成环最少要求三个节点所以每条链都要求长度>=3)求这个N的最小值。
从树的叶子节点向上推,对于每个节点,存在两种情况,1.和父节点断开(要求该节点所处的链长度>=3)。2.与父节点相连。
每个节点保存两个状态,一个是该节点的子节点个数对应的最少链的条数(Dp),一个是对应之前的子节点个数,当前节点所处的链的长度(Hav)。
这里很明显,每一个节点顶多有两个子节点,超过的话就不是条链了,所以Dp和Hav开[MAXM][3]就够了。(而且在该节点拥有两个子节点时,必须 要从父亲节点上断开。这里的子节点指的是直接连接的子节点。)
对于状态转移,更新Dp的时候,我们优先选择子节点中包含链最少的,然后再根据长度选择,越长的越好(越容易满足链长度>=3)。
为什么两个状态有优先级差距呢,或者说可以直接用贪心呢?
原因在于环的限制:
当我们要更新Dp [ i ] [ 0 ](节点 i ,拥有子节点个数 0 时的最少链数)时,长度无法造成影响,因为没有子节点相连,所以长度肯定是1,不考虑该状态直接选择包含链个数最少。
当我们要更新Dp [ i ] [ 1 ](节点 i ,拥有子节点个数 1 时的最少链数)时,因为只存在一个子链与其相连,其他全部断开,无法造成后续的影响,所以子节点包含链最少的肯定压制子节点包含链较多的,若存在个数相等的,则取长度大的)。
#include <stdio.h>
#include <algorithm>
using namespace std;
const int Size = 3;
const int MAXM = 110;
const int INF = 0x3f3f3f3f;
int Dp[MAXM][Size];
int Hav[MAXM][Size];
int Num;
int Total;
int End[MAXM];
int Data[MAXM<<1];
int Last[MAXM<<1];
void Add(int u,int v)
{
Data[Total]=u;
Last[Total]=End[v];
End[v]=Total++;
}
void init_ver(int pos)
{
Dp[pos][0]=1;Dp[pos][1]=Dp[pos][2]=INF;
Hav[pos][0]=1;Hav[pos][1]=0;
}
void Init_Build()
{
Total=0;
for(int i=1;i<=Num;i++)End[i]=-1;
int u,v;
for(int i=1;i<Num;i++)
{
scanf("%d %d",&u,&v);
Add(u,v);
Add(v,u);
}
}
void Deal(int now,int G)
{
int Zero=INF;
if(Hav[G][1]>=3)Zero=Dp[G][1];
Zero=min(Zero,Dp[G][2]);
Dp[now][2]=min(Dp[now][2]+Zero,Dp[now][1]+min(Dp[G][0],Dp[G][1])-1);
Dp[now][2]=min(INF,Dp[now][2]);
Dp[now][1]+=Zero;
if(Dp[now][0]+Dp[G][1]-1<Dp[now][1]||(Dp[now][0]+Dp[G][1]-1==Dp[now][1]&&Hav[G][1]>=Hav[now][1]))
{
Dp[now][1]=Dp[now][0]+Dp[G][1]-1;
Hav[now][1]=Hav[G][1]+1;
}
if(Dp[now][0]+Dp[G][0]-1<Dp[now][1])
{
Dp[now][1]=Dp[now][0]+Dp[G][0]-1;
Hav[now][1]=2;
}
Dp[now][0]=min(INF,Dp[now][0]+Zero);
}
void DFS(int now,int ago)
{
int pos=End[now],G;
init_ver(now);
while(~pos)
{
G=Data[pos];
if(G!=ago)
{
DFS(G,now);
Deal(now,G);
}
pos=Last[pos];
}
Hav[now][2]=0;
}
int main()
{
scanf("%d",&Num);
Init_Build();
DFS(1,0);
int best=Dp[1][2];
if(Hav[1][1]>=3)best=min(best,Dp[1][1]);
if(best==INF)best=-1;
printf("%d\n",best);
}