int main(int argc, char *argv[]) { // put command line args into variables const char *inputFile = argv[1]; const char *outputFile = argv[2]; cout << endl << "input file: " << inputFile << endl; cout << "output file: " << outputFile << endl; // use Image struct Image newImage; Image * im; im = &newImage; DisjointSets * setPointer = NULL; setPointer = new DisjointSets(1); // read image, get # of columns and rows readImage(im, inputFile); numCols = getNCols(im); numRows = getNRows(im); scanImage(im, setPointer); resolveEquivalences(im, setPointer); setColors(im, setPointer->NumSets()); writeImage(im, outputFile); return 0; }
// Add the fact that v1 and v2 are equivalent // return true if v1 was not already equivalent to v2 // and false if v1 was already equivalent to v2 bool SetEquivalent(int v1, int v2) { bool const already_equiv = false; if (v1 == v2) return already_equiv; ensureElementExists(v1); ensureElementExists(v2); const int r1 = disjoint_sets_.find_set(v1); const int r2 = disjoint_sets_.find_set(v2); if (r1 == r2) return already_equiv; root_set_map_t::const_iterator it1 = rootSetMap_.find(r1); assert(it1 != rootSetMap_.end()); std::list<int> s1 = it1->second; root_set_map_t::const_iterator it2 = rootSetMap_.find(r2); assert(it2 != rootSetMap_.end()); std::list<int> s2 = it2->second; s1.splice(s1.begin(), s2); // union the related sets disjoint_sets_.link(r1, r2); // union the disjoint sets // associate the combined related set with the new root int const new_root = disjoint_sets_.find_set(v1); if (new_root != r1) { rootSetMap_.erase(it1); } else { rootSetMap_.erase(it2); } rootSetMap_[new_root] = s1; return !already_equiv; }
static list<int> listSets(const DisjointSets &ds) { list<int> sets; for (int i = 0; i < ds.NumElements(); ++i) { if (ds.FindSet(i) == i) sets.push_front(i); } return sets; }
static list<int> listElements(const DisjointSets &ds, int set) { list<int> elements; for (int i = 0; i < ds.NumElements(); ++i) { if (ds.FindSet(i) == ds.FindSet(set)) elements.push_front(i); } return elements; }
void SquareMaze::bottomRemove(int x, int y, DisjointSets & maze,int & count,int rindex) { if (maze.find(rindex) != maze.find(rindex+maze_width)) { setWall(x, y, 1, false); maze.setunion(rindex, rindex+maze_width); count++; } }
void SquareMaze::rightRemove(int x, int y, DisjointSets & maze,int & count,int rindex) { if (maze.find(rindex) != (maze.find(rindex+1))) { setWall(x, y, 0, false); maze.setunion(rindex, rindex+1); count++; } }
// Return true if v1 and v2 are equivalent bool AreEquivalent(int v1, int v2) const { if (v1 == v2) { return true; } // The element does not exist, so we do not // know any equivalence information, // hence, v1 and v2 are not equivalent. if (!elementExists(v1) || !elementExists(v2)) { return false; } return disjoint_sets_.find_set(v1) == disjoint_sets_.find_set(v2); }
void dynamic_connected_components(EdgeListGraph& g, DisjointSets& ds) { typename graph_traits<EdgeListGraph>::edge_iterator e, end; for (tie(e,end) = edges(g); e != end; ++e) ds.link(source(*e,g),target(*e,g)); }
/* * set cannot handle over 255 elements. if this occurs, find elements * in current set, copy into a vector. push elements in the vector * into a new disjoint set, reassign pointer. * */ void expandSet(DisjointSets** s) { DisjointSets * newPointer = NULL; vector <int> currElements = getLabels(*s); cout << "expandSet()" << currElements.size() << endl; newPointer = new DisjointSets(1); for (vector<int>::iterator it = currElements.begin(); it!=currElements.end(); ++it) { cout << distance(currElements.begin(), it) << " "<< *it << endl; newPointer->AddElements(*it); } s = &newPointer; }
void initialize_dynamic_components(VertexListGraph& G, DisjointSets& ds) { typename graph_traits<VertexListGraph> ::vertex_iterator v, vend; for (tie(v, vend) = vertices(G); v != vend; ++v) ds.make_set(*v); }
// Return the representative for the node v. int FindSet(int v) const { // If element does not exist if (!elementExists(v)) { // Then it is its own root. // This avoids adding singleton sets to the partition. return v; } return disjoint_sets_.find_set(v); }
/** * Finds a minimal spanning tree on a graph. * THIS FUNCTION IS GRADED. * * @param graph - the graph to find the MST of * * @todo Label the edges of a minimal spanning tree as "MST" * in the graph. They will appear blue when graph.savePNG() is called. * * @note Use your disjoint sets class from MP 7.1 to help you with * Kruskal's algorithm. Copy the files into the libdsets folder. * @note You may call std::sort (http://www.cplusplus.com/reference/algorithm/sort/) * instead of creating a priority queue. */ void GraphTools::findMST(Graph & graph) { vector<Edge> eds = graph.getEdges(); sort(eds.begin(), eds.end(),myfunction); DisjointSets vers; vector <Vertex> vertex_list = graph.getVertices(); vers.addelements(vertex_list.size()); for (int i = 0; i < eds.size(); i++) { Vertex u = eds[i].source; Vertex v = eds[i].dest; if (vers.find(u) != vers.find(v)) { vers.setunion(u,v); graph.setEdgeLabel(u,v,"MST"); } } }
// Return a list of elements that are in the same disjoint set // as v. std::list<int> GetRelatedSet(int v) const { std::list<int> ret; if (!elementExists(v)) { ret.push_back(v); return ret; } int root = disjoint_sets_.find_set(v); root_set_map_t::const_iterator it = rootSetMap_.find(root); assert(it!=rootSetMap_.end()); return it->second; }
// If v does not exist, then add it to the disjoint set. void ensureElementExists(int v) const { elements_t::const_iterator it = elements_.find(v); if (it == elements_.end()) { disjoint_sets_.make_set(v); elements_.insert(v); std::list<int> li; li.push_front(v); rootSetMap_[v] = li; } return; }
/** * Finds a minimal spanning tree on a graph. * THIS FUNCTION IS GRADED. * * @param graph - the graph to find the MST of * * @todo Label the edges of a minimal spanning tree as "MST" * in the graph. They will appear blue when graph.savePNG() is called. * * @note Use your disjoint sets class from MP 7.1 to help you with * Kruskal's algorithm. Copy the files into the libdsets folder. * @note You may call std::sort (http://www.cplusplus.com/reference/algorithm/sort/) * instead of creating a priority queue. */ void GraphTools::findMST(Graph & graph) { vector<Edge> theEdges = graph.getEdges(); std::sort(theEdges.begin(), theEdges.end()); DisjointSets theVertexSet; vector<Vertex> theVertices = graph.getVertices(); theVertexSet.addelements(theVertices.size()); int size = theVertices.size(); int count = 0; vector<Edge>::iterator iter; for(iter = theEdges.begin(); iter != theEdges.end(); iter++) { if(count == size - 1) break; if(theVertexSet.find(iter->source) != theVertexSet.find(iter->dest)) { theVertexSet.setunion(iter->source, iter->dest); graph.setEdgeLabel(iter->source, iter->dest, "MST"); count++; } } }
void __output_ancestors(Vertex from, Vertex const u, Vertex const v) { sets.make_set(from); ancestors[sets.find_set(from)] = from; VertexContainer child = children(from); for (VertexContainer::iterator ite = child.begin(); ite != child.end(); ++ite) { __output_ancestors(*ite, u, v); sets.union_set(from, *ite); ancestors[sets.find_set(from)] = from; } colors[from] = black; if (u == from && colors[v] == black) { printf("The least common ancestor of %d and %d is %d.\n", query_dat(u), query_dat(v), query_dat(ancestors[sets.find_set(v)])); } else if (v == from && colors[u] == black) { printf("The least common ancestor of %d and %d is %d.\n", query_dat(v), query_dat(u), query_dat(ancestors[sets.find_set(u)])); } }
void SquareMaze::makeMaze(int width, int height) { right.clear(); bottom.clear(); maze_width = width; maze_height = height; blocks = maze_width * maze_height; right.resize(blocks,true); bottom.resize(blocks,true); DisjointSets maze; maze.addelements(blocks); srand(time(NULL)); //int x, y; bool rightmost=true, bottommost=true; int count = 0; //int rindex; while (count< (blocks - 1)) { int rindex = rand() % blocks; int x = rindex%maze_width; int y = rindex/maze_width; if(x==(maze_width-1)) rightmost=true; else rightmost=false; if(y==(maze_height-1)) bottommost=true; else bottommost=false; if (( rightmost == true ) && ( bottommost == true )) { rightmost=rightmost; } else if (!rightmost && !bottommost) { int action=rand()%3; if (action == 0) rightRemove(x,y, maze,count,rindex); else if (action == 1) bottomRemove(x,y, maze,count,rindex); else { if ((maze.find(rindex) != maze.find(rindex+1)) && (maze.find(rindex) != maze.find(rindex+maze_width))&& (maze.find(rindex+1) != maze.find(rindex+1))) { setWall(x, y, 0, false); setWall(x, y, 1, false); maze.setunion(rindex, rindex+1); maze.setunion(rindex, rindex+maze_width); count+=2; } } } else if(bottommost) { int action=rand()%2; if (action== 1)rightRemove(x,y, maze,count,rindex); } else { int action =rand()%2; if (action == 1)bottomRemove(x,y, maze,count,rindex); } } }
void reset() { ancestors.clear(); colors.clear(); sets.clear(); }
void printElementSets(const DisjointSets & s) { for (int i = 0; i < s.NumElements(); ++i) cout << s.FindSet(i) << " "; cout << endl; }
void SquareMaze::makeMaze(int width,int height) { width1=width; height1=height; int size=width*height; right.clear(); down.clear();//clearing right and down walls just in case right=vector<bool>(size, true);//set all walls so they are there we will remove later down=vector<bool>(size, true); vector<int> blocks(size);//vector for indicies // map<int, int> maps; for(int i=0;i<size; i++) { blocks.push_back(i);//pushing back the indidces for the maze // for(int j=0; j<height1; j++) // { // // maps.insert(make_pair(i,j)); // } } DisjointSets set; set.addelements(size);//used to stop cycles from being created srand(time(0)); // std::random_shuffle(maps.begin(), maps.end()); std::random_shuffle(blocks.begin(), blocks.end());//randomly shuffles indicies so it doesnt create the same maze // map<int, int>::iterator it; vector<int> :: iterator it; for(it=blocks.begin(); it!=blocks.end(); it++) { int x=*it%width;//x and y coords for the index int y=*it/width; int index=*it; //actual index if(x!=width1-1 ) //cant go any farther to the right in this case so dont want to do it { int index1=index+1; if(set.find(index)!=set.find(index1)) //checking if the one to the right of the index is in the same set { setWall(x,y,0,false);//if they are not in the same set we can remove the wall set.setunion(index, index1); //we connect them so they are in the same set //works because if we try to remove something in the same set it will create a cycle } } if(y!=height1-1) { int index2=index+width1; if(set.find(index)!= set.find(index2)) { setWall(x,y,1,false); //do the same for if we want to go down set.setunion(index, index2); } } } }
//compute bag affiliation for all vertices //store result in m_bagindex void ClusterAnalysis::computeBags() { const Graph &G = m_C->constGraph(); // Storage structure for results m_bagindex.init(G); // We use Union-Find for chunks and bags DisjointSets<> uf; NodeArray<int> setid(G); // Index mapping for union-find #if 0 node* nn = new node[G.numberOfNodes()]; // dito #endif // Every cluster gets its index ClusterArray<int> cind(*m_C); // We store the lists of cluster vertices List<node>* clists = new List<node>[m_C->numberOfClusters()]; int i = 0; // Store index and detect the current leaf clusters List<cluster> ccleafs; ClusterArray<int> unprocessedChildren(*m_C); //processing below: compute bags for(cluster c : m_C->clusters) { cind[c] = i++; if (c->cCount() == 0) ccleafs.pushBack(c); unprocessedChildren[c] = c->cCount(); } // Now we run through all vertices, storing them in the parent lists, // at the same time, we initialize m_bagindex for(node v : G.nodes) { // setid is constant in the following setid[v] = uf.makeSet(); // Each vertex v gets its own ClusterArray that stores v's bag index per cluster. // See comment on use of ClusterArrays above m_bagindex[v] = new ClusterArray<int>(*m_C,DefaultIndex, m_C->maxClusterIndex()+1);//m_C->numberOfClusters()); cluster c = m_C->clusterOf(v); // Push vertices in parent list clists[cind[c]].pushBack(v); } // Now each clist contains the direct vertex descendants // We process the clusters bottom-up, compute the chunks // of the leafs first. At each level, for a cluster the // vertex lists of all children are concatenated // (could improve this by having an array of size(#leafs) // and concatenating only at child1), then the bags are // updated as follows: chunks may be linked by exactly // the edges with lca(c) ie the ones in m_lcaEdges[c], // and bags may be built by direct child clusters that join chunks. // While concatenating the vertex lists, we can check // for the vertices in each child if the uf number is the same // as the one of a first initial vertex, otherwise we join. // First, lowest level clusters are processed: All chunks are bags OGDF_ASSERT(!ccleafs.empty()); while (!ccleafs.empty()){ const cluster c = ccleafs.popFrontRet(); Skiplist<int*> cbags; //Stores bag indexes ocurring in c auto storeResult = [&] { for (node v : clists[cind[c]]) { int theid = uf.find(setid[v]); (*m_bagindex[v])[c] = theid; if (!cbags.isElement(&theid)) { cbags.add(new int(theid)); } // push into list of outer active vertices if (m_storeoalists && isOuterActive(v, c)) { (*m_oalists)[c].pushBack(v); } } (*m_bags)[c] = cbags.size(); // store number of bags of c }; if (m_storeoalists){ //no outeractive vertices detected so far (*m_oalists)[c].clear(); } //process leafs separately if (c->cCount() == 0) { //Todo could use lcaEdges list here too, see below for (node u : c->nodes) { for(adjEntry adj : u->adjEntries) { node w = adj->twinNode(); if (m_C->clusterOf(w) == c) { uf.link(uf.find(setid[u]),uf.find(setid[w])); } } } // Now all chunks in the leaf cluster are computed // update for parent is done in the else case storeResult(); } else { // ?We construct the vertex list by concatenating // ?the lists of the children to the current list. // We need the lists for storing the results efficiently. // (Should be slightly faster than to call clusterNodes each time) // Bags are either links of chunks by edges with lca==c // or links of chunk by child clusters. // Edge links for(edge e : (*m_lcaEdges)[c]) { uf.link(uf.find(setid[e->source()]),uf.find(setid[e->target()])); } // Cluster links for(cluster cc : c->children) { //Initial id per child cluster cc: Use value of first //vertex, each time we encounter a different value in cc, //we link the chunks //add (*itcc)'s vertices to c's list ListConstIterator<node> itvc = clists[cind[cc]].begin(); int inid; if (itvc.valid()) inid = uf.find(setid[*itvc]); while (itvc.valid()) { int theid = uf.find(setid[*itvc]); if (theid != inid) uf.link(inid,theid); clists[cind[c]].pushBack(*itvc); ++itvc; } } storeResult(); } // Now we update the status of the parent cluster and, // in case all its children are processed, add it to // the process queue. if (c != m_C->rootCluster()) { OGDF_ASSERT(unprocessedChildren[c->parent()] > 0); unprocessedChildren[c->parent()]--; if (unprocessedChildren[c->parent()] == 0) ccleafs.pushBack(c->parent()); } } // clean up delete[] clists; }
// Normalize the partition so that the smallest element // is the root. // TODO this would be easy to maintain incrementally. // But I don't think boost does not. void Normalize() const { disjoint_sets_.normalize_sets(elements_.begin(), elements_.end()); }
void deleteCell(unsigned row, unsigned column) { auto &cell = cells[row][column]; if (cell.getState() != Cell::State::Unknown) { throw MultipleStateChangeException(); } auto rOffs = 0; auto cOffs = -1; for (auto i = 0; i < 4; i++) { const auto r = row + rOffs; const auto c = column + cOffs; if (r >= 0 && r < size && c >= 0 && c < size && cells[r][c].getState() == Cell::State::Deleted) { throw NoSolutionExistsException("deleted neighbor found"); } auto t = rOffs; rOffs = -cOffs; cOffs = t; } const auto cellSet = static_cast<int>(row * size + column + 1); if (row == 0 || row == size - 1 || column == 0 || column == size - 1) { deletedTrees.unionSets(0, cellSet); } rOffs = -1; cOffs = -1; for (auto i = 0; i < 4; i++) { const auto r = row + rOffs; const auto c = column + cOffs; const auto diagonalNeighborSet = static_cast<int>(r * size + c + 1); if (r >= 0 && r < size && c >= 0 && c < size && cells[r][c].getState() == Cell::State::Deleted) { const auto diagonalRoot = deletedTrees.findSet(diagonalNeighborSet); const auto cellRoot = deletedTrees.findSet(cellSet); if (diagonalRoot != cellRoot) { deletedTrees.linkSets(diagonalRoot, cellRoot); } else { throw NoSolutionExistsException("circular neighbors found"); } } auto t = rOffs; rOffs = -cOffs; cOffs = t; } cell.setState(Cell::State::Deleted); const auto value = cell.getValue(); rowCounts[row][value]--; columnCounts[column][value]--; unknownCellCount--; rOffs = 0; cOffs = 1; for (auto i = 0; i < 4; i++) { const auto r = row + rOffs; const auto c = column + cOffs; if (r >= 0 && r < size && c >= 0 && c < size && cells[r][c].getState() == Cell::State::Unknown) { finalizeCell(r, c); } auto t = rOffs; rOffs = -cOffs; cOffs = t; } }
// Return the number of disjoint sets in the partition. std::size_t CountSets() const { return disjoint_sets_.count_sets(elements_.begin(), elements_.end()); }