1 //It is made by Awson on 2017.9.20
2 #include <set>
3 #include <map>
4 #include <cmath>
5 #include <ctime>
6 #include <queue>
7 #include <stack>
8 #include <string>
9 #include <cstdio>
10 #include <vector>
11 #include <cstdlib>
12 #include <cstring>
13 #include <iostream>
14 #include <algorithm>
15 #define Min(a, b) ((a) < (b) ? (a) : (b))
16 #define Max(a, b) ((a) > (b) ? (a) : (b))
17 #define LL long long
18 using namespace std;
19 const int N = 20000;
20 const int INF = ~0u>>1;
21
22 struct tt {
23 int to, cost, next;
24 }edge[N*2+5];
25 int path[N+5], top;
26 int n, u, v, c;
27 int ans;
28 bool vis[N+5];
29 int size[N+5], mx[N+5], minsize, root;
30 int f[N+5][3];
31
32 int gcd(int a, int b) {
33 return b == 0 ? a : gcd(b, a%b);
34 }
35 void add(int u, int v, int c) {
36 edge[++top].to = v;
37 edge[top].cost = c;
38 edge[top].next = path[u];
39 path[u] = top;
40 }
41 void get_size(int u, int fa) {
42 size[u] = 1; mx[u] = 0;
43 for (int i = path[u]; i; i = edge[i].next)
44 if (!vis[edge[i].to] && edge[i].to != fa) {
45 get_size(edge[i].to, u);
46 size[u] += size[edge[i].to];
47 mx[u] = Max(mx[u], size[edge[i].to]);
48 }
49 }
50 void get_root(int r, int u, int fa) {
51 mx[u] = Max(mx[u], size[r]-size[u]);
52 if (mx[u] < minsize) minsize = mx[u], root = u;
53 for (int i = path[u]; i; i = edge[i].next)
54 if (!vis[edge[i].to] && edge[i].to != fa)
55 get_root(r, edge[i].to, u);
56 }
57 void get_ans(int u, int fa) {
58 f[u][0] = 1;
59 f[u][1] = f[u][2] = 0;
60 for (int i = path[u]; i; i = edge[i].next)
61 if (!vis[edge[i].to] && edge[i].to != fa) {
62 get_ans(edge[i].to, u);
63 f[u][edge[i].cost%3] += f[edge[i].to][0];
64 f[u][(1+edge[i].cost)%3] += f[edge[i].to][1];
65 f[u][(2+edge[i].cost)%3] += f[edge[i].to][2];
66 }
67 }
68 void solve(int x) {
69 minsize = INF;
70 int flag[3] = {0};
71 get_size(x, 0);
72 get_root(x, x, 0);
73 vis[root] = true;
74 f[root][0] = 1;
75 f[root][1] = f[root][2] = 0;
76 for (int i = path[root]; i; i = edge[i].next)
77 if (!vis[edge[i].to]) {
78 get_ans(edge[i].to, 0);
79 flag[edge[i].cost%3] = f[edge[i].to][0];
80 flag[(1+edge[i].cost)%3] = f[edge[i].to][1];
81 flag[(2+edge[i].cost)%3] = f[edge[i].to][2];
82 ans -= flag[0]*flag[0] + flag[1]*flag[2]*2;
83 f[root][0] += flag[0];
84 f[root][1] += flag[1];
85 f[root][2] += flag[2];
86 }
87 ans += f[root][0]*f[root][0] + f[root][1]*f[root][2]*2;
88 for (int i = path[root]; i; i = edge[i].next)
89 if (!vis[edge[i].to])
90 solve(edge[i].to);
91 }
92 void work() {
93 for (int i = 1; i < n; i++) {
94 scanf("%d%d%d", &u, &v, &c);
95 c %= 3;
96 add(u, v, c); add(v, u, c);
97 }
98 ans = 0;
99 solve(1);
100 int tmp = gcd(ans, n*n);
101 printf("%d/%d\n", ans/tmp, n*n/tmp);
102 }
103 int main() {
104 while (~scanf("%d", &n))
105 work();
106 return 0;
107 }