题目链接:http://codeforces.com/contest/1189/problem/D2
题意:现在有一颗 n n n个节点的树,树的边上有一个权值(保证为偶数),你需要将一个空树(形状和给出的树相同边权为 0 0 0)变成给出的树,在空树中,你可以多次任意选树的两个叶子节点,然后选择一个整数,将两个叶子节点路径上的所有边权值加上这个整数,问是否可以将这个空树变成给出的树,如果不能输出 N O NO NO,否则输出 Y E S YES YES并且输出你每次选择的叶子节点和权值。
解题心得:
#include
using namespace std;
typedef complex<double> cp;
typedef long long ll;
typedef pair<int,int> P;
const ll maxn = 1010;
const double pi = acos(-1);
map <pair<int, int>, int> maps;//用于记录这条边是否被处理过
struct Edge {
//记录每次操作选择的叶子节点和值
int u, v, val;
};
int n, degree[maxn];//记录每个节点的度
vector <pair<int, int>> ve[maxn];//记录树的边
vector <Edge> ans;//记录答案
void init() {
scanf("%d", &n);
for(int i=1;i<n;i++) {
int a, b, c;
scanf("%d%d%d",&a, &b, &c);
ve[a].push_back(make_pair(b, c));//建立双向边
ve[b].push_back(make_pair(a, c));
degree[a]++;
degree[b]++;
}
}
bool Impossible() {
//判断不可能的情况
for(int i=1;i<=n;i++) {
if(degree[i] == 2) {
return true;
}
}
return false;
}
vector <int> node[2];//记录边连接的两个节点对应方向的两个叶子节点,如果自身是叶子节点就将自身压入
void find_node(int father, int v, int index) {
//找非叶子节点的另一个方向的两个叶子节点
if(degree[v] == 1) {
node[index].push_back(v);
return ;
}
for(int i=0;i<ve[v].size();i++) {
int to = ve[v][i].first;
if(to == father) continue;
find_node(v, to, index);
return ;
}
}
void get_ans(int u, int v, int val) {
if(degree[u] != 1) {
//判断u是否是叶子节点,不是就去找另外两个叶子节点
for(int i=0;i<ve[u].size();i++) {
int to = ve[u][i].first;
if(to == v) continue;
else {
find_node(u, to, 0);
if(node[0].size() == 2) break;
}
}
} else {
node[0].push_back(u);
}
if(degree[v] != 1) {
//判断v是否是叶子节点,不是就去找另外两个叶子节点
for(int i=0;i<ve[v].size();i++) {
int to = ve[v][i].first;
if(to == u) continue;
else {
find_node(v, to, 1);
if(node[1].size() == 2) break;
}
}
} else {
node[1].push_back(v);
}
if(node[0].size() == 2) {
//各种条件下有不同的答案
ans.push_back({
node[0][0], node[0][1], -val/2});
if(node[1].size() == 2) {
ans.push_back({
node[1][0], node[1][1], -val/2});
ans.push_back({
node[0][0], node[1][0], val/2});
ans.push_back({
node[0][1], node[1][1], val/2});
} else {
ans.push_back({
node[0][1], node[1][0], val/2});
ans.push_back({
node[0][0], node[1][0], val/2});
}
} else {
if(node[1].size() == 2) {
ans.push_back({
node[1][0], node[1][1], -val/2});
ans.push_back({
node[0][0], node[1][0], val/2});
ans.push_back({
node[0][0], node[1][1], val/2});
} else {
ans.push_back({
node[0][0], node[1][0], val});
}
}
node[0].clear();
node[1].clear();
}
void solve() {
for(int i=1;i<=n;i++) {
for(int j=0;j<ve[i].size();j++) {
int to = ve[i][j].first;
int u = i;
if(u > to) swap(u, to);
if(maps.count(make_pair(u, to)) != 0) continue;//处理过的边就不再处理
maps[make_pair(u, to)] = 1;
get_ans(i, to, ve[u][j].second);
}
}
}
int main() {
// freopen("1.in.txt", "r", stdin);
init();
if(Impossible()) {
puts("NO");
return 0;
} else {
puts("YES");
}
solve();
printf("%d\n", ans.size());
for(int i=0;i<ans.size();i++) {
Edge now = ans[i];
printf("%d %d %d\n",now.u, now.v, now.val);
}
return 0;
}