题目链接:Here!
题目大意:给你一种树的边的合成方式,问你经过数次合成之后,能否变成线性结构,如果可以,求出这个结构最短的长度。
解题思路:按照拓扑排序的顺序,从度数为1的点开始“删去”,对于每一个节点用set保存从其他节点到这个节点的长度,如果有相同长度的就会自动“合并”。所以,只有两种情况是满足条件的:
1.有一个节点的set的大小是2,其余的都是1
2.全部节点的set的大小都是1
对于情况1,答案就是set中两个数的和;对于情况2,答案就是所有节点中set中的值最大的那个。
若答案为偶数,则根据题意,一定可以再进行一次合成,所以将答案除2直到为奇数即为最终答案。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <set>
#include <list>
#include <deque>
#define LL long long
#define INF 0x3f3f3f3f
#define PII pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define lowbit(x) (x&(-x))
using namespace std;
const int N = 2e5+5;
vector<int>e[N];
set<int>s[N];
queue<int>q;
bool vis[N];
int d[N];
int main(){
int n;scanf("%d",&n);
for(int i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
d[u]++,d[v]++;
e[u].pb(v),e[v].pb(u);
}
for(int i=1;i<=n;i++)
if(d[i]==1)q.push(i),s[i].insert(0);
while(q.size()){
int tp=q.front();q.pop();vis[tp]=true;
for(int i=0;i<e[tp].size();i++){
int v=e[tp][i];
if(vis[v])continue;
d[v]--;
s[v].insert(*(s[tp].begin())+1);
if(d[v]==1&&s[v].size()==1)q.push(v);
}
}
int cnt=0,ans=0;
for(int i=1;i<=n;i++)
if(s[i].size()>2||s[i].size()==0)return 0*puts("-1");
else if(s[i].size()==1)ans=max(ans,*s[i].begin());
else cnt++,ans=max(ans,(*s[i].begin())+(*s[i].rbegin()));
if(cnt>1)puts("-1");
else{
while(ans%2==0)ans/=2;
printf("%d\n",ans);
}
return 0;
}
注:本文参考了
http://www.cnblogs.com/qscqesze/p/6401615.html的解法