分析:
这个题看起来像是个树形dp,嗯,就是看起来像。
所以我们就按树形dp的思路去分析就好了,这个题是一个树形dp的变形题。
和以前建树是一样的,我们用邻接表来进行储存。利用邻接表的特性,我们可以先加左边的点,再加右边的点,这样遍历的时候就可以先左后右了。
分析题意后我们设立几个数组:
(邻接表的就不说了,大家应该都会吧)
f [ i ] :表示使 i 这棵子树满足条件,所需要的最小的步数。
dep[ i ]:表示 i 这一个点的深度
maxdep[ i ]:表示 i 这个点的子树中风铃的最大深度
mindep[ i ]:同理表示 i 这个点的子树中风铃的最小深度
最后就是怎么样去写转移方程啦。
通过读题我们可以知道,在一棵树一定是一棵二叉树,所以我们就只需要将两棵子树相加就好了。
完成了???
并没有,我们是不是忘记了题目里的条件,题目中要求我们选一个满足下面两个条件的风铃:
(1) 所有的玩具都在同一层(也就是说,每个玩具到天花板之间的杆的个数是一样的)或至多相差一层。
(2) 对于两个相差一层的玩具,左边的玩具比右边的玩具要更靠下一点。
所以我们在状态转移方程里加一个小小的判断
if((abs(maxdep[c[1]] - mindep[c[2]]) > 1) || (abs(mindep[c[1]] - maxdep[c[2]]) > 1) || (maxdep[c[1]] > mindep[c[2]] && maxdep[c[2]] > mindep[c[1]])){ printf("-1"); exit(0); }
这次是真的完成了??
是哒
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 400005; inline int read(){ int f = 1 , x = 0; char ch = getchar(); while(ch > '9' || ch < '0'){if(ch == '-')f = -1;ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + ch - '0';ch = getchar();} return x * f; } int n,u,v; struct Edge{ int from,to,next; }edge[maxn << 1]; int head[maxn],tot; int f[maxn],w[maxn],cnt,c[maxn],dep[maxn]; int maxdep[maxn],mindep[maxn]; void add(int u,int v){ edge[++tot].from = u; edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot; } void dfs(int x,int fa){ for(int i=head[x];i;i=edge[i].next){ int v = edge[i].to; if(v != fa){ dep[v] = dep[x] + 1; dfs(v , x); mindep[x] = min(mindep[x] , mindep[v]); maxdep[x] = max(maxdep[x] , maxdep[v]); } } if(w[x] == -1) mindep[x] = maxdep[x] = dep[x]; else { int num = 0; for(int i=head[x];i;i=edge[i].next){ int v = edge[i].to; if(v != fa) c[++num] = v;//两个儿子 } if((abs(maxdep[c[1]] - mindep[c[2]]) > 1) || (abs(mindep[c[1]] - maxdep[c[2]]) > 1) || (maxdep[c[1]] > mindep[c[2]] && maxdep[c[2]] > mindep[c[1]])){ printf("-1"); exit(0); } f[x] = f[c[1]] + f[c[2]] + (mindep[c[1]] < maxdep[c[2]] ? 1 : 0); } } int main(){ n = read(); cnt = n; for(int i=1;i<=n;i++){ u = read(); v = read(); if(v == -1){ v = ++cnt; w[cnt] = -1; } add(v , i); add(i , v); if(u == -1){ u = ++cnt; w[cnt] = -1; } add(i , u); add(u , i); } memset(mindep , 0x3f , sizeof(mindep)); memset(maxdep , 0 , sizeof(maxdep)); dfs(1 , 0); printf("%d ",f[1]); return 0; }