Jenny's Subtrees
Problem Statement :
Jenny loves experimenting with trees. Her favorite tree has n nodes connected by n - 1 edges, and each edge is ` unit in length. She wants to cut a subtree (i.e., a connected part of the original tree) of radius r from this tree by performing the following two steps: 1. Choose a node, x , from the tree. 2. Cut a subtree consisting of all nodes which are not further than r units from node x . For example, the blue nodes in the diagram below depict at x = 1 subtree centered at that has radius r = 2 Given n, r , and the definition of Jenny's tree, find and print the number of different subtrees she can cut out. Two subtrees are considered to be different if they are not isomorphic. Input Format The first line contains two space-separated integers denoting the respective values of n and r. Each of the next n - 1 subsequent lines contains two space-separated integers, x and y, describing a bidirectional edge in Jenny's tree having length 1. Output Format Print the total number of different possible subtrees.
Solution :
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) {
//Delete father from adjacency list
vector <int> :: iterator it = find(tree[node].begin(), tree[node].end(), father);
if (it != tree[node].end())
tree[node].erase(it);
//Solve sons
sz[node] = 1;
for (vector <int> :: iterator it = tree[node].begin(); it != tree[node].end(); ++ it) {
dfsMorph(*it, node);
sz[node] += sz[*it];
}
//Find hash of node
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()
{
//freopen("input.in", "r", stdin);
//InputReader cin;
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()
View More Similar Problems
Print the Elements of a Linked List
This is an to practice traversing a linked list. Given a pointer to the head node of a linked list, print each node's data element, one per line. If the head pointer is null (indicating the list is empty), there is nothing to print. Function Description: Complete the printLinkedList function in the editor below. printLinkedList has the following parameter(s): 1.SinglyLinkedListNode
View Solution →Insert a Node at the Tail of a Linked List
You are given the pointer to the head node of a linked list and an integer to add to the list. Create a new node with the given integer. Insert this node at the tail of the linked list and return the head node of the linked list formed after inserting this new node. The given head pointer may be null, meaning that the initial list is empty. Input Format: You have to complete the SinglyLink
View Solution →Insert a Node at the head of a Linked List
Given a pointer to the head of a linked list, insert a new node before the head. The next value in the new node should point to head and the data value should be replaced with a given value. Return a reference to the new head of the list. The head pointer given may be null meaning that the initial list is empty. Function Description: Complete the function insertNodeAtHead in the editor below
View Solution →Insert a node at a specific position in a linked list
Given the pointer to the head node of a linked list and an integer to insert at a certain position, create a new node with the given integer as its data attribute, insert this node at the desired position and return the head node. A position of 0 indicates head, a position of 1 indicates one node away from the head and so on. The head pointer given may be null meaning that the initial list is e
View Solution →Delete a Node
Delete the node at a given position in a linked list and return a reference to the head node. The head is at position 0. The list may be empty after you delete the node. In that case, return a null value. Example: list=0->1->2->3 position=2 After removing the node at position 2, list'= 0->1->-3. Function Description: Complete the deleteNode function in the editor below. deleteNo
View Solution →Print in Reverse
Given a pointer to the head of a singly-linked list, print each data value from the reversed list. If the given list is empty, do not print anything. Example head* refers to the linked list with data values 1->2->3->Null Print the following: 3 2 1 Function Description: Complete the reversePrint function in the editor below. reversePrint has the following parameters: Sing
View Solution →