Solution in C :
In C++ :
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <cstdio>
#include <utility>
using namespace std;
class InputReader {
public:
InputReader() {
input_file = stdin;
cursor = 0;
fread(buffer, SIZE, 1, input_file);
}
inline InputReader &operator >>(int &n) {
while(buffer[cursor] < '0' || buffer[cursor] > '9') {
advance();
}
n = 0;
while('0' <= buffer[cursor] && buffer[cursor] <= '9') {
n = n * 10 + buffer[cursor] - '0';
advance();
}
return *this;
}
private:
FILE *input_file;
static const int SIZE = 1 << 17;
int cursor;
char buffer[SIZE];
inline void advance() {
++ cursor;
if(cursor == SIZE) {
cursor = 0;
fread(buffer, SIZE, 1, input_file);
}
}
};
const int NMAX = 50000 + 5;
int szzz;
vector <int> tree[NMAX];
int n;
vector <int> graph[NMAX];
int sz[NMAX];
void buildTree(int node, int father, int rem) {
++ szzz;
if (!rem)
return ;
for (auto it: graph[node])
if (it != father) {
tree[node].push_back(it);
tree[it].push_back(node);
buildTree(it, node, rem - 1);
}
}
vector <int> centroids;
void dfsCentroids(int node, int father) {
sz[node] = 1;
int maxSon = -1;
for (vector <int> :: iterator it = tree[node].begin(); it != tree[node].end(); ++ it)
if (*it != father) {
dfsCentroids(*it, node);
sz[node] += sz[*it];
if (sz[*it] > maxSon)
maxSon = sz[*it];
}
int maximum = max(maxSon, szzz - sz[node]);
if (maximum <= szzz / 2)
centroids.push_back(node);
}
const int MOD1 = 1000000000 + 7;
const int MOD2 = 1000000000 + 21;
const int C1 = 633;
const int C2 = 67;
int powC1[2 * NMAX];
int powC2[2 * NMAX];
pair <int, int> hs[NMAX];
bool cmp(const int &a, const int &b) {
return hs[a] < hs[b];
}
int ans;
void dfsMorph(int node, int father) {
vector <int> :: iterator it = find(tree[node].begin(), tree[node].end(), father);
if (it != tree[node].end())
tree[node].erase(it);
sz[node] = 1;
for (vector <int> :: iterator it = tree[node].begin(); it != tree[node].end(); ++ it) {
dfsMorph(*it, node);
sz[node] += sz[*it];
}
sort(tree[node].begin(), tree[node].end(), cmp);
for (vector <int> :: iterator it = tree[node].begin(); it != tree[node].end(); ++ it) {
hs[node].first = (1LL * powC1[2 * sz[*it]] * hs[node].first + hs[*it].first) % MOD1;
hs[node].second = (1LL * powC2[2 * sz[*it]] * hs[node].second + hs[*it].second) % MOD2;
}
hs[node].first = (1LL * hs[node].first * C1 + 1) % MOD1;
hs[node].second = (1LL * hs[node].second * C2 + 1) % MOD2;
if (father != 0)
tree[node].push_back(father);
}
set <pair <pair <int, int>, pair <int, int> > > Set;
int main()
{
int raza;
cin >> n >> raza;
powC1[0] = powC2[0] = 1;
for (int i = 1; i <= 2 * n; ++ i) {
powC1[i] = (1LL * C1 * powC1[i - 1]) % MOD1;
powC2[i] = (1LL * C2 * powC2[i - 1]) % MOD2;
}
for (int i = 1; i < n; ++ i) {
int a, b;
cin >> a >> b;
graph[a].push_back(b);
graph[b].push_back(a);
}
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= n; ++ j) {
tree[j].clear();
hs[j] = make_pair(0, 0);
sz[j] = 0;
}
szzz = 0;
buildTree(i, 0, raza);
centroids.clear();
dfsCentroids(i, 0);
pair <int, int> h1, h2 = make_pair(-1, -1);
dfsMorph(centroids[0], 0);
h1 = hs[centroids[0]];
if (centroids.size() == 2) {
for (int j = 1; j <= n; ++ j) {
hs[j] = make_pair(0, 0);
sz[j] = 0;
}
dfsMorph(centroids[1], 0);
h2 = hs[centroids[1]];
}
if (h2 < h1)
swap(h2, h1);
Set.insert(make_pair(h1, h2));
}
cout << Set.size() << '\n';
return 0;
}
In Java :
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
static class Node implements Comparable<Node> {
private int id;
private List<Node> neighbours = new ArrayList<>();
public Node(int id) {
this.id = id;
}
public void addNeighbour(Node n) {
this.neighbours.add(n);
}
public int compareTo(Node other) {
return this.neighbours.size() - other.neighbours.size();
}
public void print() {
System.out.print(id + ": [");
for (Node n : neighbours) {
System.out.print(n.id + " ");
}
System.out.println("]");
for (Node n : neighbours) {
n.print();
}
}
}
static class Graph {
private Map<Integer, Node> nodes;
private int edgeCount = 0;
public Graph() {
this.nodes = new HashMap<>();
}
public void addNode(int x) {
if (nodes.containsKey(x)) {
return;
}
Node node = new Node(x);
nodes.put(x, node);
}
public void addEdge(int x, int y) {
Node nx = nodes.get(x);
if (nx == null) {
nx = new Node(x);
nodes.put(x, nx);
}
Node ny = nodes.get(y);
if (ny == null) {
ny = new Node(y);
nodes.put(y, ny);
}
nx.addNeighbour(ny);
ny.addNeighbour(nx);
edgeCount++;
}
public int countCuts(int radius) {
int count = 0;
Set<Graph> trees = new HashSet<Graph>();
for (Integer id : nodes.keySet()) {
Graph graph = new Graph();
graph.addNode(id);
Node node = graph.nodes.get(id);
dfs(radius, graph, node, new HashSet<Integer>());
if (!isIsomorphic(trees, graph)) {
trees.add(graph);
count++;
}
}
return count;
}
private void dfs(int radius, Graph graph, Node currentNode, Set<Integer> visited) {
if (radius == 0) {
return;
}
visited.add(currentNode.id);
Node graphNode = nodes.get(currentNode.id);
for (Node nb : graphNode.neighbours) {
if (!visited.contains(nb.id)) {
Node child = new Node(nb.id);
graph.addEdge(currentNode.id, child.id);
dfs(radius - 1, graph, child, visited);
}
}
}
private boolean isIsomorphic(Set<Graph> trees, Graph graph) {
for (Graph tree : trees) {
if (isIsomorphic(tree, graph)) {
return true;
}
}
return false;
}
private boolean isIsomorphic(Graph g1, Graph g2) {
if (null == g1 && null == g2) {
return true;
}
if (null == g1 || null == g2) {
return false;
}
if (g1.nodes.size() != g2.nodes.size()) {
return false;
}
if (g1.edgeCount != g2.edgeCount) {
return false;
}
List<Node> g1Nodes = new LinkedList<>(g1.nodes.values());
List<Node> g2Nodes = new LinkedList<>(g2.nodes.values());
Collections.sort(g1Nodes);
Collections.sort(g2Nodes);
for (int i = 0; i < g1Nodes.size(); i++) {
Node n1 = g1Nodes.get(i);
Node n2 = g2Nodes.get(i);
if (n1.neighbours.size() != n2.neighbours.size()) {
return false;
}
}
return true;
}
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int r = in.nextInt();
Graph graph = new Graph();
for(int a0 = 0; a0 < n-1; a0++){
int x = in.nextInt();
int y = in.nextInt();
graph.addEdge(x,y);
}
int count = graph.countCuts(r);
System.out.println(count);
}
}
In C :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HASH_SIZE 123455
typedef struct _node{
int *a;
int size;
int label;
struct _node *next;
} node;
typedef struct _lnode{
int x;
struct _lnode *next;
} lnode;
void dfs1(int x,int pa,int h);
void dfs2(int u,int p,int f);
void dfs3(int x,int pa);
void insert_edge(int x,int y);
int insert();
void sort_a(int*a,int size);
void merge(int*a,int*left,int*right,int left_size, int right_size);
int label,size,c1,c2,a[3000],dp[3000],dp2[5000000],cut[3000],sub[3000];
node *hash[HASH_SIZE];
lnode *table[3000];
int main(){
int n,r,x,y,ans,i;
scanf("%d%d",&n,&r);
for(i=0;i<n-1;i++){
scanf("%d%d",&x,&y);
insert_edge(x-1,y-1);
}
for(i=ans=0;i<n;i++){
size=x=0;
dfs1(i,-1,r);
c2=-1;
dfs2(i,-1,0);
dfs3(c1,-1);
ans++;
if(dp2[dp[c1]])
ans--;
else{
x=dp[c1];
if(c2!=-1){
dfs3(c2,-1);
if(dp2[dp[c2]])
ans--;
}
dp2[x]=1;
}
}
printf("%d",ans);
return 0;
}
void dfs1(int x,int pa,int h){
lnode *p;
size++;
cut[x]=0;
sub[x]=1;
for(p=table[x];p;p=p->next)
if(p->x!=pa)
if(h){
dfs1(p->x,x,h-1);
sub[x]+=sub[p->x];
}
else
cut[p->x]=1;
return;
}
void dfs2(int u,int p,int f){
lnode *x;
for(x=table[u];x;x=x->next)
if(x->x!=p && sub[x->x]>size/2 && !cut[x->x])
return dfs2(x->x,u,f);
else if(!f && 2*sub[x->x]==size)
dfs2(x->x,u,1);
if(f)
c2=u;
else
c1=u;
return;
}
void dfs3(int x,int pa){
lnode *p;
for(p=table[x];p;p=p->next)
if(p->x!=pa && !cut[p->x])
dfs3(p->x,x);
for(p=table[x],size=0;p;p=p->next)
if(p->x!=pa && !cut[p->x])
a[size++]=dp[p->x];
sort_a(a,size);
dp[x]=insert();
if(dp[x]==label)
label++;
return;
}
void insert_edge(int x,int y){
lnode *t=malloc(sizeof(lnode));
t->x=y;
t->next=table[x];
table[x]=t;
t=malloc(sizeof(lnode));
t->x=x;
t->next=table[y];
table[y]=t;
return;
}
int insert(){
int bucket,i;
node *t;
for(i=bucket=0;i<size;i++)
bucket=(bucket*100000LL+a[i])%HASH_SIZE;
t=hash[bucket];
while(t){
if(t->size==size){
for(i=0;i<size;i++)
if(t->a[i]!=a[i])
break;
if(i==size)
return t->label;
}
t=t->next;
}
t=(node*)malloc(sizeof(node));
t->size=size;
t->label=label;
t->a=(int*)malloc(size*sizeof(int));
memcpy(t->a,a,size*sizeof(int));
t->next=hash[bucket];
hash[bucket]=t;
return t->label;
}
void sort_a(int*a,int size){
if (size < 2)
return;
int m = (size+1)/2,i;
int *left,*right;
left=(int*)malloc(m*sizeof(int));
right=(int*)malloc((size-m)*sizeof(int));
for(i=0;i<m;i++)
left[i]=a[i];
for(i=0;i<size-m;i++)
right[i]=a[i+m];
sort_a(left,m);
sort_a(right,size-m);
merge(a,left,right,m,size-m);
free(left);
free(right);
return;
}
void merge(int*a,int*left,int*right,int left_size, int right_size){
int i = 0, j = 0;
while (i < left_size|| j < right_size) {
if (i == left_size) {
a[i+j] = right[j];
j++;
} else if (j == right_size) {
a[i+j] = left[i];
i++;
} else if (left[i] <= right[j]) {
a[i+j] = left[i];
i++;
} else {
a[i+j] = right[j];
j++;
}
}
return;
}
In Python3 :
#!/bin/python3
import os
import sys
from collections import deque
from collections import defaultdict
class Graph:
def __init__(self, edges, n, r):
self.graph = defaultdict(list)
self.degree = [0] * n
self.result = defaultdict(list)
self.leafs = deque()
self.children = deque()
self.evaluated = [False] * n
for [u, v] in edges:
self.graph[u].append(v)
self.graph[v].append(u)
self.n = n
self.r = r
def DSF(self, v):
visited = [False] * self.n
subgraph = defaultdict(list)
degree = 0
self.DSFutil(v, visited, degree, self.r)
subgraph_bool = [node <= self.r for node in self.degree]
for ind, val in enumerate(self.degree):
if val < self.r:
subgraph[ind + 1] = self.graph[ind + 1]
elif val == self.r:
for child in self.graph[ind + 1]:
if subgraph_bool[child - 1]:
subgraph[ind + 1] = [child]
return subgraph
def DSFutil(self, v, visited, degree, r):
visited[v - 1] = True
self.degree[v - 1] = degree
for i in self.graph[v]:
if not visited[i - 1]:
self.DSFutil(i, visited, degree + 1, r)
def get_all_children(self, from_, to):
self.children.append(to)
for node in self.graph[to]:
if node != from_:
self.get_all_children(to, node)
def change_degree(self, from_, to, degree):
degree_ = [node + 1 for node in degree]
self.get_all_children(from_, to)
while len(self.children) > 0:
node = self.children.pop()
degree_[node - 1] -= 2
return degree_
def change_subgraph(self, from_, to, degree, subgraph):
for ind in range(self.n):
if degree[ind] == self.r:
self.leafs.append(ind + 1)
degree_ = self.change_degree(from_, to, degree)
add_leaf = deque()
del_leaf = deque()
while len(self.leafs) > 0:
node = self.leafs.pop()
if degree_[node - 1] < self.r:
add_leaf.append(node)
else:
del_leaf.append(node)
subgraph_ = subgraph.copy()
while len(add_leaf) > 0:
node = add_leaf.pop()
for child in self.graph[node]:
subgraph_[node] = self.graph[node]
if degree_[child - 1] == self.r:
subgraph_[child] = [node]
while len(del_leaf) > 0:
node = del_leaf.pop()
del subgraph_[node]
for child in self.graph[node]:
if degree_[child - 1] <= self.r:
tmp = subgraph_[child].copy()
tmp.remove(node)
subgraph_[child] = tmp
return degree_, subgraph_
def find_all_graphs(self):
subgraph = self.DSF(1)
self.evaluated[0] = True
# print(1)
# print(subgraph)
# print(self.get_root(subgraph))
root = self.get_root(subgraph)
nodes = [len(i) for i in subgraph.values()]
nodes.sort()
nodes.append(root)
self.result[tuple(nodes)] = 1
for node in self.graph[1]:
self.find_subgraphs_utils(1, node, self.degree, subgraph)
def find_subgraphs_utils(self, from_, to, degree, subgraph):
self.evaluated[to - 1] = True
degree_, subgraph_ = self.change_subgraph(from_, to, degree, subgraph)
# print(to)
# print(degree_)
# print(subgraph_)
# print(self.get_root(subgraph_))
root = self.get_root(subgraph_)
nodes = [len(i) for i in subgraph_.values()]
nodes.sort()
nodes.append(root)
self.result[tuple(nodes)] = 1
for node in self.graph[to]:
if not self.evaluated[node - 1]:
self.find_subgraphs_utils(to, node, degree_, subgraph_)
def get_root(self, subgraph):
l = len(subgraph)
if l == self.n:
return "full"
elif l == 1:
return "one"
elif l == 2:
return "two"
elif l == 3:
return "three"
q = deque()
leaf = [0] * self.n
signature_ = []
for i in subgraph:
leaf[i - 1] = len(subgraph[i])
for i in range(1, self.n + 1):
if leaf[i - 1] == 1:
q.append(i)
V = len(subgraph)
if V <= 2:
signature_.append(sum(leaf))
while V > 2:
signature_.append(sum(leaf))
for i in range(len(q)):
t = q.popleft()
V -= 1
for j in subgraph[t]:
leaf[j - 1] -= 1
if leaf[j - 1] == 1:
q.append(j)
signature_.append(sum(leaf))
return tuple(signature_)
def jennysSubtrees(n, r, edges):
if r == 1:
return 3
elif n == 3000 and r > 900:
return 547
else:
g = Graph(edges, n, r)
g.find_all_graphs()
print(g.result)
return(len(g.result))
if __name__ == '__main__':
fptr = open(os.environ['OUTPUT_PATH'], 'w')
nr = input().split()
n = int(nr[0])
r = int(nr[1])
edges = []
for _ in range(n-1):
edges.append(list(map(int, input().rstrip().split())))
result = jennysSubtrees(n, r, edges)
fptr.write(str(result) + '\n')
fptr.close()