CodeForces 765E. Tree Folding
来源:互联网 发布:风险评价矩阵法 编辑:程序博客网 时间:2024/05/22 06:33
题面:
time limit per test : 2 seconds memory limit per test : 512 megabytes input : standard input output :standard output
Vanya wants to minimize a tree. He can perform the following operation multiple times: choose a vertex v, and two disjoint (except for v) paths of equal length a0 = v, a1, …, ak, and b0 = v, b1, …, bk. Additionally, vertices a1, …, ak, b1, …, bk must not have any neighbours in the tree other than adjacent vertices of corresponding paths. After that, one of the paths may be merged into the other, that is, the vertices b1, …, bk can be effectively erased:
Help Vanya determine if it possible to make the tree into a path via a sequence of described operations, and if the answer is positive, also determine the shortest length of such path.
Input
The first line of input contains the number of vertices n (2 ≤ n ≤ 2·105).
Next n - 1 lines describe edges of the tree. Each of these lines contains two space-separated integers u and v (1 ≤ u, v ≤ n, u ≠ v) — indices of endpoints of the corresponding edge. It is guaranteed that the given graph is a tree.
Output
If it is impossible to obtain a path, print -1. Otherwise, print the minimum number of edges in a possible path.
题意:
可以对一颗树进行选取某一个地方作为中点,合并两条完全不重合且长度相同的链,直到这个树最后成为一条链。问这条链按照这样操作最后最短长度是?如果这棵树不能成为一条链,输出 -1.
思考:
按照样例给的树,加上随手画几棵树,可以发现,这个树最后能够合并成一条链,那他的根就是他原来形状直径(树上最长的一条链)的中点。知道根后,就好做呢,从根出发,判断每个子节点出发的链能不能合并的的条件就是这些子节点深度有没有一样。这个过程一个dfs就可以搞定。
先从根节点开始dfs。
对于每一个节点,用一个set记录:以该点为根的子树的深度。
a) 如果此节点的某个子节点个数大于2表示无法满足最后合成一条链,直接返回-1.
b) 若set的元素个数<=1,那么,以该点为根的子树,显然是可以缩成一条链,且该点为链的端点。
c) 若set元素个数=2,只有当该点为根才满足成为一条链。
d)最后注意如果链长度为偶数,注定还可以合并。
#include<bits/stdc++.h>using namespace std;template<int N,int M>//N点的个数,M边的个数struct Graph{ int top; struct Vertex{ int head; }V[N]; struct Edge{ int v,next; }E[M]; void init(){ memset(V,-1,sizeof(V)); top = 0; } void add_edge(int u,int v){ E[top].v = v; E[top].next = V[u].head; V[u].head = top++; }};const int N=2*1e5+10;Graph<N,N*2>g;int d[N],dl[N],dr[N];void dfs(int u,int f,int dep,int *d){ d[u]=dep; for(int i=g.V[u].head;i!=-1;i=g.E[i].next){ int v=g.E[i].v; if(v==f) continue; dfs(v,u,dep+1,d); }}int solve(int u,int f){ set<int>st; for(int i=g.V[u].head;i!=-1;i=g.E[i].next){ int v=g.E[i].v; if(v==f) continue; int t=solve(v,u); if(t==-1) return -1; st.insert(t+1); } if(st.size()==0) return 0; if(st.size()==1) return *st.begin(); if(st.size()==2&&f==0) return *st.rbegin()+*st.begin(); return -1;}int main(){ int n; while(~scanf("%d",&n)){ g.init(); for(int i=1;i<n;i++){ int a,b;scanf("%d %d",&a,&b); g.add_edge(a,b); g.add_edge(b,a); } int l=1,r=1;//这段代码找树上直径以及中点 dfs(1,0,0,d); for(int i=1;i<=n;i++) if(d[i]>d[l]) l=i; dfs(l,0,0,dl); for(int i=1;i<=n;i++) if(dl[i]>dl[r]) r=i; dfs(r,0,0,dr); int rt=l; for(int i=1;i<=n;i++){//找到l,r两点之间的中点就是我们要dfs树的根 if(dl[i]+dr[i]==dl[r]&&min(dl[i],dr[i])>min(dl[rt],dr[rt])) rt=i; } int ans=solve(rt,0); while(ans%2==0) ans/=2; printf("%d\n",ans); }}
其实如果没有发现根是树直径中点的规律,也没有关系,随便选一点,一直dfs只要出现该节点的深度个数为 2,并且还有父亲的情况下就以当前节点为根继续搜下去判断满不满足条件。详见以下代码。
#include<bits/stdc++.h>using namespace std;template<int N,int M>//N点的个数,M边的个数struct Graph{ int top; struct Vertex{ int head; }V[N]; struct Edge{ int v,next; }E[M]; void init(){ memset(V,-1,sizeof(V)); top = 0; } void add_edge(int u,int v){ E[top].v = v; E[top].next = V[u].head; V[u].head = top++; }};const int N=2*1e5+10;Graph<N,N*2>g;int root;int dfs(int u,int f){ set<int>st; for(int i=g.V[u].head;i!=-1;i=g.E[i].next){ int v=g.E[i].v; if(v==f) continue; int t=dfs(v,u); if(t==-1) return -1; st.insert(t+1); } if(st.size()==0) return 0; if(st.size()==1) return *st.begin(); if(st.size()==2&&f==0) return *st.rbegin()+*st.begin(); if(st.size()>=3) return-1; root=u; return -1;}int main(){ int n; while(~scanf("%d",&n)){ g.init(); root=0; for(int i=1;i<=n;i++){ int a,b;scanf("%d %d",&a,&b); g.add_edge(a,b); g.add_edge(b,a); } int ans=dfs(1,0); if(ans==-1&&root) ans=dfs(root,0); while(ans%2==0) ans/=2; printf("%d\n",ans); }}
- CodeForces 765E. Tree Folding
- CodeForces 765E. Tree Folding
- Codeforces 765E - Tree Folding 【树,dfs/bfs】
- Codeforces 765E. Tree Folding 题目详解+错点记录
- Codeforces Round #397 E. Tree Folding
- Codeforces Round #397 E. Tree Folding(脑洞)
- Codeforces Round #397 Problem E. Tree Folding 解题报告
- Codeforces Round #397 - E - Tree Folding (找树中直径,dfs)
- Codeforces Round #397 E. Tree Folding (树形dp)
- Codeforces Round #397 Tree Folding
- Codeforces Round #397(Div. 1 + Div. 2 combined)E. Tree Folding【思维+Dfs】dalao们的解法真巧妙系列QAQ
- Codeforces 716E E. Digit Tree
- Codeforces Gym 101142 F. Folding
- Codeforces 463E Caisa and Tree(暴力)
- codeforces 23E Tree (树形dp)
- Codeforces 337E Divisor Tree 暴搜
- Codeforces 620 E. New Year Tree
- Codeforces 620E New Year Tree
- IP多薄路由协议
- 深度神经网络(DNN)反向传播算法(BP)
- 探索大规模线程吞吐量处理器的内存一致性
- 找不到链接库之Target Membership
- 乐舞app client 反编译
- CodeForces 765E. Tree Folding
- Java中LinkList类的使用
- 每天一个 Linux 命令(4):mkdir
- leetcode121、122、123
- 协同过滤算法与推荐系统
- LintCode 86:Binary Search Tree Iterator
- 父类、子类、接口、多态
- WebService(7)_Apache CXF拦截器-权限管理-登录验证
- 信息论——JS散度(Jensen-Shannon)