#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=2e4+5; const int INF=0x7fffffff; inline int read() { char c=getchar();int num=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num; } inline int gcd(int a,int b) { int c; while(b) { c=a,a=b,b=c%b; } return a; } int n,ans; int head[N],num_edge; struct Edge { int v,w,nxt; }edge[N<<1]; void add_edge(int u,int v,int w) { edge[++num_edge].v=v; edge[num_edge].w=w; edge[num_edge].nxt=head[u]; head[u]=num_edge; } bool vis[N]; int Siz,root; int siz[N],mxson[N]; void getroot(int u,int fa) { siz[u]=1,mxson[u]=0; for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; if(v==fa||vis[v]) continue; getroot(v,u); siz[u]+=siz[v]; if(mxson[u]<siz[v]) mxson[u]=siz[v]; } mxson[u]=max(mxson[u],Siz-mxson[u]); if(mxson[u]<mxson[root]) root=u; } int dis[N],cnt[N]; void getdis(int u,int fa) { ++cnt[dis[u]]; for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; if(vis[v]||v==fa) continue; dis[v]=dis[u]+edge[i].w, dis[v]%=3; getdis(v,u); } } int solve(int u,int dist) { cnt[0]=cnt[1]=cnt[2]=0; dis[u]=dist%3; getdis(u,0); return cnt[1]*cnt[2]*2+cnt[0]*cnt[0]; } void divide(int u) { ans+=solve(u,0); vis[u]=1; for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; if(vis[v]) continue; ans-=solve(v,edge[i].w); root=0,Siz=siz[v]; getroot(v,0); divide(root); } } int main() { n=read(); for(int i=1,u,v,w;i<n;++i) { u=read(),v=read(),w=read(); add_edge(u,v,w); add_edge(v,u,w); } mxson[0]=INF,Siz=n; getroot(1,0); divide(root); int a=n*n; if(a==ans) puts("1"); else { int g=gcd(ans,a); printf("%d/%d",ans/g,a/g); } return 0; }