F. Almost All
题意:
给你n个点的树,n-1条边,权值不知道,让你给每条边填上权值,权值1~(2* n*n/9)的值至少出现一次,其他随意,最后将每一条边输出(包括权值)。
分析:
首先找到树的重心,然后以树的重心开始依次填数字,我们要将树分成两半,对于节点多的一半,我们依次填当前节点到他上一个节点为1的距离,最终用now记录每颗子树的节点个数,那么对于下一个子树,就从now开始编号,也是当前节点到他上一个节点为1的距离,如果这个不懂画一下图就明白了,那么对于另外一半,怎么填呢?就是从now+1开始填和前面一样的方法。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=1e3+5;
struct node{int to,next;}edges[MAXN<<1];
int head[MAXN],edge;
int dp[MAXN]; //每个孩子节点的个数
int n; //n个节点
int root,max_root; //重心
int fa[MAXN]; //父节点
void add(int u,int v)
{
edges[edge].to=v;
edges[edge].next=head[u];
head[u]=edge++;
}
void dfs(int u,int p)//树的重心
{
dp[u]=1;
fa[u]=p;
int max_val=0;
for(int i=head[u];i!=-1;i=edges[i].next)
{
int v=edges[i].to;
if(v==p)continue;
dfs(v,u);
dp[u]+=dp[v];
max_val=max(max_val,dp[v]);
}
max_val=max(max_val,n-dp[u]);
if(max_val<max_root)
{
max_root=max_val;
root=u;
}
}
vector<pair<int,int> >s,S1,S2;
int now,tot;
int to[MAXN];
void dfs1(int u,int p)
{
to[u]=++now;
printf("%d %d %d\n",u,p,(now-to[p])*(tot+1));
for(int i=head[u];i!=-1;i=edges[i].next)
{
int v=edges[i].to;
if(v==p)continue;
dfs1(v,u);
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<=n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
max_root=0x3f3f3f3f;
dfs(1,0);
for(int i=head[root];i!=-1;i=edges[i].next) //将以root为根的树的子树进行排序
{
int v=edges[i].to;
if(v==fa[root])s.push_back(make_pair(n-dp[root],v));
else s.push_back(make_pair(dp[v],v));
}
sort(s.begin(),s.end()); //从小到大排序
reverse(s.begin(),s.end()); //从大到小排序
int sum1=0,sum2=0;
for(int i=0;i<s.size();i++) //将其分成两半
{
if(sum1>sum2)sum2+=s[i].first,S2.push_back(s[i]);
else sum1+=s[i].first,S1.push_back(s[i]);
}
if(S1.size()<S2.size())swap(S1,S2);
now=0,tot=0;
to[root]=0;
for(int i=0;i<S1.size();i++)
{
dfs1(S1[i].second,root);
}
tot=now;now=0;
for(int i=0;i<S2.size();i++)
{
dfs1(S2[i].second,root);
}
return 0;
}