// BigBrother (vertex cover 10) --- mjd@cs.auckland.ac.nz // #include #include #include #include #include #include #include //#define WATCH #define NODEBUG using namespace std; typedef vector NLIST; // node (neighbor) list typedef vector< NLIST > ADJLIST; class Graph // view as undirected graph { private: ADJLIST adj; // adjacency lists. public: // creators + destroyers // Graph(int n) : adj(n) { } Graph(const Graph &G) : adj(G.adj) {} ~Graph() {} // stream I/0 // friend ostream& operator<<(ostream&, const Graph&); friend istream& operator>>(istream&, Graph&); // mutators // bool addArc(int u, int v) { if ( isArc(u,v) ) return false; adj[u].push_back(v); return true; } bool addEdge(int u, int v) { return addArc(u,v) && addArc(v,u); } // accessors // int order() const { return adj.size(); } bool isArc(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; } bool isUndirected() const { int n=order(); for (int i=0; i=0 && u u) *it = *it - 1; it++; } } adj.erase(adj.begin()+u); // finally delete list for u } }; ostream& operator<<(ostream& o, const Graph& G) { o << G.order() << "\n"; for (int i=0; i>(istream& in, Graph& G) { string line; int n; getline(in,line); istringstream lineIn(line); lineIn >> n; G.adj.resize(n); for (int i=0; i> deg; int v2; while (lineIn>>v2) { assert(v1!=v2); bool ans=G.addArc(v1,v2); assert(ans); deg--; } assert(deg==0); } return in; } //---------------------------------------------------------------------- // checks for potential VC -- assume cover is a sorted list of vertices. bool checkCover(const Graph &G, const vector &cover, int k) { int n = G.order(); int c=0; for (int i=0; i::const_iterator it = find( cover.begin(), cover.end(), N[j] ); if ( it==cover.end() ) { return false; } } } return true; } /* * Pick all k subsets of a graph and see if G\{v1,v2,...vk} has * any edges. */ bool vcLazy(const Graph &G, int k) { int n = G.order(); if ( k >= n ) return true; vector cover(k); int i; for (i=0; i=0; i--) { if (cover[i] < n-(k-i)) { cover[i]++; for (int j=i+1; j k then answer 'no', other remove these b vertices. // 3) If the resulting graph has more than k * (k-b) edges answer 'no'. // 4) Use brute-force algorithm on remaining graph with k' = k-b. // bool vcBuss(Graph &G, int k) { int n=G.order(); if ( k >= n-1 ) return true; if (G.size()==0) return true; if ( k == 0 ) return false; if ( k <= 1 ) return vcLazy(G,k); // cut-off to exhaustive search vector deg(n); int b = 0; // number of big degree vertices for (int i=0; ij) { G.rmNode(i); G.rmNode(j); } else { G.rmNode(j); G.rmNode(i); } return vcBuss(G,k-1); } if (deg[i] > k) b++; } if (b==0) { // do decision tree search Graph G0(G), G1(G); int e = G.neighbors(0).at(0); G0.rmNode(0); G1.rmNode(e); Graph G01(G1); if (deg[0] >= deg[e]) // try largest deg of 0 and e in VC first { if (vcBuss(G0,k-1)) return true; if (vcBuss(G1,k-1)) return true; } else { if (vcBuss(G1,k-1)) return true; if (vcBuss(G0,k-1)) return true; } G01.rmNode(0); // delete both 0 and e (1 was deleted above) return vcBuss(G01,k-2); } else if (b>k) return false; else { for (int i=n-1; i>=0; i--) // do in reverse to preserve deg values { if (deg[i] > k) G.rmNode(i); } if (G.size() > k*(k-b)) return false; else if (G.size() <= k-b) return true; return vcBuss(G,k-b); } } //---------------------------------------------------------------------- int main(int argc, char** argv) { int k=10; if (argc > 1) k = atoi(argv[1]); int x=0; while (true) { Graph G(0); cin >> G; int n=G.order(); if (n==0) break; assert(n<=2500); assert( G.isUndirected() ); cout << "Graph " << ++x << ": " << (vcBuss(G,k)? "yes":"no") << endl; //cout << "Graph " << ++x << ": " << (vcLazy(G,k)? "yes":"no") << endl; } }