题目链接
题目大意
有一棵树给你边的指定权值,和上一题一样,每次可以把两个叶子结点的最短路径上加上任意的整数值,所以在有限次数下能不能把这个树加成指定权值。
解题思路
和上一题一样,当有一个点的度数为2的时候,就输出NO
其余情况,我们考虑:当现在要加的这个边的两个顶点都不是叶子节点,边权为x,那么:
我们设这个边为(u,v)点a,b是点u的子树中的两个叶子结点,b,c是点v子树中的两个叶子结点,这个图大概长这个样子:
然后我们把a-d这个边加x/2,把c-d这个边加x/2,a-b这个边加-x/2,c-d这个边加-x/2
如果u是叶子结点,那么a-b这个边就不用管了,如果v是叶子节点,那么c-d这个边就不用管了,就这么模拟一下就好
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=1005;
struct node
{
int v,nex;
};
node e[N*4];
int f[N],vis[N],u[N],v[N],w[N],a,b,c,d,tot;
struct Node
{
int u,v,w;
Node(){}
Node(int U,int V,int W)
{
u=U;
v=V;
w=W;
}
};
vector<Node>G;
void add(int u,int v)
{
e[tot].v=v;
e[tot].nex=f[u];
f[u]=tot++;
}
void dfs1(int u,int fa)
{
int flag=0;
for(int i=f[u];i!=-1;i=e[i].nex)
{
int v=e[i].v;
if(v!=fa)
{
dfs1(v,u);
flag=1;
}
}
if(!flag)
{
if(a==0)
a=u;
b=u;
}
}
void dfs2(int u,int fa)
{
int flag=0;
for(int i=f[u];i!=-1;i=e[i].nex)
{
int v=e[i].v;
if(v!=fa)
{
dfs2(v,u);
flag=1;
}
}
if(!flag)
{
if(c==0)
c=u;
d=u;
}
}
int main()
{
memset(f,-1,sizeof(f));
memset(vis,0,sizeof(vis));
int n,x,y,z;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d %d %d",&u[i],&v[i],&w[i]);
add(u[i],v[i]);
add(v[i],u[i]);
vis[u[i]]++;
vis[v[i]]++;
}
int flag=0;
for(int i=1;i<=n;i++)
{
if(vis[i]==2)
flag=1;
}
if(flag)
printf("NO\n");
else
{
for(int i=1;i<n;i++)
{
x=u[i];y=v[i];z=w[i];
a=0;b=0,c=0;d=0;
dfs1(x,y);
dfs2(y,x);
G.push_back(Node(a,c,z/2));
G.push_back(Node(b,d,z/2));
if(a!=b)
G.push_back(Node(a,b,-z/2));
if(c!=d)
G.push_back(Node(c,d,-z/2));
}
printf("YES\n");
printf("%d\n",G.size());
for(int i=0;i<G.size();i++)
printf("%d %d %d\n",G[i].u,G[i].v,G[i].w);
}
return 0;
}