// Isotrees mjd@cs.auckland.ac.nz // #include #include #include #include #include /* * Simple (Free/Rooted) Tree Graph Data Structure */ #ifndef TREE_H #define TREE_H using namespace std; typedef vector NLIST; // node (neighbor) list typedef vector< NLIST > ADJLIST; // graph data structure class Tree { protected: ADJLIST adj; // adjacency lists. Tree(int n) : adj(n) { } // for rooted tree public: // creators + destroyers // Tree() : adj(1) { } // single vertex tree ~Tree() {} // stream I/0 // friend ostream& operator<<(ostream&, const Tree&); friend ostream& operator<<(ostream&, const class rTree&); friend istream& operator>>(istream&, Tree&); // accessors // int order() const { return adj.size(); } bool isEdge(int u, int v) const { int n = order(); assert(u >= 0 && u < n); assert(v >= 0 && v < n); assert(u != v); NLIST::const_iterator it = find( adj[u].begin(), adj[u].end(), v ); if ( it==adj[u].end() ) return false; else return true; } int degree(int u) const { return adj[u].size(); } void center(int &c1, int &c2) const; const NLIST neighbors(int u) const { return (const NLIST&) adj[u]; } // mutators // void addNode(int u) { int n = order(); assert(u>=0 && upush_back(u); adj.push_back(*L); adj[u].push_back(n); } // tree isomorphism // bool operator==(const Tree& T) const; }; class rTree : public Tree { private: int root; // adjacency lists. public: // creators + destroyers // rTree() : Tree(), root(0) {} // single vertex tree rTree(int n, int r=0) : Tree(n), root(r) {} ~rTree() {} void setRoot(int r) { assert(r>(istream&, rTree&); }; #endif /* * Simple Tree Data Structure */ // center (if c2==-1) or bicenter of a tree // void Tree::center(int &c1, int &c2) const { int n = order(); vector deg(n); int i; for (i=0; i leaves; int j; for (j=0; j0) deg[adj[leaves[j]][k]] = d-1; } } assert (cnt==n-1 || cnt==n-2); c1 = c2 = -1; for (i=n-1; i>=0; i--) { if (deg[i]==1) { if (cnt++ == n-2) c2=i; else c1=i; } if (deg[i]==0) { assert(cnt==n-1); c1=i; } } } typedef vector CertSeq; static CertSeq getCertificate(const Tree &T, int r, vector &seen) { assert(seen[r]==false); seen[r]=true; vector< CertSeq > seq; for (int i=0; i seen1(n1); fill(seen1.begin(),seen1.end(),false); vector seen2(n2); fill(seen2.begin(),seen2.end(),false); CertSeq c1=getCertificate(T1,r1,seen1); CertSeq c2=getCertificate(T2,r2,seen2); for (int i=0; igetRoot(), T, T.getRoot()); } ostream& operator<<(ostream& o, const Tree& G) { o << G.order() << "\n"; for (int i=0; i &P, int r) { const NLIST N=T.neighbors(r); for (int i=0; i parents(n); fill(parents.begin(),parents.end(),-2); parents[G.getRoot()] = -1; getParents(G, parents, G.getRoot()); o << n; for (int i=0; i>(istream& in, Tree& G) // adjacency list { char line[LLEN]; int n; in.getline(line, LLEN); istringstream lineIn(line); lineIn >> n; G.adj.resize(n); for (int i=0; i>v2) { assert( !G.isEdge(v1,v2) ); //G.addEdge(v1,v2); G.adj[v1].push_back(v2); } } return in; } // n p_1 p_2 ... p_n // p_i = parent (i.e., 0..n-1) or -1 for root // istream& operator>>(istream& in, rTree& G) { int n; in >> n; G.adj.resize(n); for (int i=0; i> v2; if ( v2 == -1 ) { G.setRoot(v1); continue; } G.adj[v1].push_back(v2); G.adj[v2].push_back(v1); } return in; } typedef vector< CertSeq > EQtreesC; using namespace std; int main(int argc, char **argv) { int seq=0; int cnt=0; int n; while (true) { cin >> n; if (n==0) break; EQtreesC rootList; rTree T; cin >> T; cout << seq++ << ": 0"; cnt=1; vector seen(T.order()); fill(seen.begin(),seen.end(),false); CertSeq cert=getCertificate(T,T.getRoot(),seen); rootList.push_back(cert); for (int i=1; i> T; seen.resize(T.order()); fill(seen.begin(),seen.end(),false); cert=getCertificate(T,T.getRoot(),seen); int j; for (j=0; j