【luogu3621】【APIO2007】风铃(树形DP)
2017-10-18 09:39
453 查看
题目描述:
风铃传送门
算法:
树形DP
做法:
首先说明,我的做法比较麻烦,但思路是很清晰的。
1. 看看是否满足条件一
用一个 dfs 求出所有结点的深度,并看看满不满足条件一
2. 看看有没有解
dfs 一遍,对每一个结点 u 求一个 h[u],其中
h[u]=1 表示 u 子树内的所有风铃都是最深的
h[u]=2 表示 u 子树内的所有风铃都是最浅的
h[u]=3 表示 u 子树内的风铃有深有浅
设 v1 和 v2 分别为 u 的两个孩子,若 h[v1]=3并且h[v2]=3,那么无解。
3. 求解
dfs 一遍,满足
(h[u的左孩子]!=1并且h[u的右孩子]==1)或者(h[u的左孩子]==2并且h[u的右孩子]==3)
就需要交换一次。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=100010; int n, mi; int f [2]; int Md, ans, M; // M:风铃的最大深度-1 Md:第一个遇见的风铃深度-1 int dep , h ; // h[u]=1 表示 u 子树内的所有风铃都是最深的 // h[u]=2 表示 u 子树内的所有风铃都是最浅的 // h[u]=3 表示 u 子树内的风铃有深有浅 bool dfs1(int u){ // 检验是否满足条件 1 if(f[u][0]!=-1){ dep[f[u][0]] = dep[u]+1; if(!dfs1(f[u][0])) return false; }else{ M = max(M, dep[u]); if(Md==0) Md = dep[u]; else if(dep[u]-Md>1 || dep[u]-Md<-1) return false; } if(f[u][1]!=-1){ dep[f[u][1]] = dep[u]+1; if(!dfs1(f[u][1])) return false; }else{ M = max(M, dep[u]); if(Md==0) Md = dep[u]; else if(dep[u]-Md>1 || dep[u]-Md<-1) return false; } return true; } bool dfs2(int u){ // 检验是否有解 if(f[u][0]!=-1){ if(!dfs2(f[u][0])) return false; h[u] = h[f[u][0]]; } else h[u] = (dep[u]==M ? 1 : 2); if(f[u][1]!=-1){ int v = f[u][1]; if(!dfs2(v)) return false; if(h[u]==3 && h[v]==3) return false; if(h[v]==3 || (h[u]==2 && h[v]==1) || (h[u]==1 && h[v]==2)) h[u]=3; }else{ if(dep[u]==M){ if(h[u]!=1) h[u]=3; } else if(h[u]!=2) h[u]=3; } return true; } void dfs3(int u){ // 计算答案 int v; if(f[u][0]!=-1 && f[u][1]!=-1){ dfs3(f[u][0]); dfs3(f[u][1]); } if((h[f[u][0]]!=1 && h[f[u][1]]==1) || (h[f[u][0]]==2 && h[f[u][1]]==3)) ans++; } int main(){ scanf("%d",&n); for(int i=1, a1, a2; i<=n; ++i){ scanf("%d%d", &a1, &a2); f[i][0] = a1; f[i][1] = a2; // 因为是二叉树,且每一个点的左右孩子都已确定,就不用邻接表了 } dep[1] = 1; if(!dfs1(1)){ puts("-1"); return 0; } if(!dfs2(1)){ puts("-1"); return 0; } dfs3(1); printf("%d\n",ans); while(1); }
相关文章推荐
- 【BZOJ1149】【APIO2007】风铃(完全二叉树+dp)
- BZOJ 2809 [Apio2012]dispatching(斜堆+树形DP)
- 树形DP——Luogu2014 选课
- bzoj1060 [ZJOI2007]时态同步 [树形dp][贪心…]
- 解题报告 APIO 2007 风铃
- APIO2010 巡逻 树形DP
- bzoj 1060: [ZJOI2007]时态同步【树形dp】
- bzoj 3677: [Apio2014]连珠线【树形dp】
- BZOJ 1060: [ZJOI2007]时态同步 树形DP
- BZOJ 1093 [ZJOI 2007] 最大半连通子图 (tarjan+树形DP)
- BZOJ1149:[CTSC/APIO2007]风铃——题解
- BZOJ 3677【Apio2014】连珠线 树形dp
- 树形DP——BZOJ1060/Luogu1131 [ZJOI2007]时态同步
- [BZOJ1060][ZJOI2007]时态同步(树形dp)
- [bzoj1060][ZJOI2007]时态同步 树形DP
- BZOJ 1060 ZJOI 2007 时态同步 树形DP
- 【BZOJ 1060】 1060: [ZJOI2007]时态同步 (树形DP)
- 【bzoj1060】[ZJOI2007]时态同步 树形dp
- BZOJ 1060: [ZJOI2007]时态同步( 树形dp )
- bzoj 1060: [ZJOI2007]时态同步 树形dp