Algorithm logic: backtracking and brute force.
The following two versions are reproduced:
Version 1
0.032 MSAC.
// Servicing stations (service station) // PC/ultraviolet A IDs: 110804/10160, popularity: B, success rate: Low Level: 3 // verdict: accepted // submission date: 2011-08-10 // UV Run Time: 0.056 S // copyright (c) 2011, Qiu. Metaphysis # Yeah dot net // the essence of this question is to find the number of vertices in the smallest Dominant Set of the graph. The problem of finding the smallest Dominant Set of graphs is an NP-complete problem. Currently, there is no efficient algorithm. // If You Want to enumerate all the subsets of a set, enumerate it. But wait a moment, the enumeration requires an order. First, enumerate the subsets with a small number of elements. Otherwise, enumerating a subset with a large number of elements may waste time, after all, from enumeration of a subset with a small number of elements to a large subset with a large number of elements, you can ensure that you can find the smallest governing set without wasting more time. Oh, time is money, isn't it? When can a strong person find the p-time algorithm for np-hard question/question, or prove that p = NP is enough? I hope I can see it in my lifetime !! //// To improve efficiency and reduce program running time, the following optimization methods are used: // (1) if the graph can be split into multiple unconnected subgraphs, then, the number of vertices in the smallest governing set of the subgraph is summed up (previously caused by the/not split graph, resulting in multiple TLE ). // (2) bitwise operations are used to evaluate two sets. The adjacent table of a vertex is expressed as an integer in advance to replace the union of the Set // with the operator. // (3) Consider vertices with high degrees before enumeration. //// For the enumeration method, refer to [J. loughry, J. i. van hemert, L. schoofs, efficiently enumerating // the subsets of a set, 2000] # include <iostream> # include <vector> # include <algorithm> # include <set> using namespace STD; # define max_town 35 typedef long unsigned lluint; bool finish; int minimum; vector <lluint> edge; lluint target_tag, origin_tag; // check whether the vertex set is a dominant set. Void check (INT flag [], int position) {int Index = 0; lluint new_tag = origin_tag, old_tag = origin_tag; For (INT I = 0; I <edge. size (); I ++) {If (index <position) & (flag [Index] = I) {new_tag | = edge [I]; if (new_tag> old_tag) old_tag = new_tag; elsereturn; index ++ ;}} if (new_tag = target_tag) {minimum = index; finish = true ;}} // enumerate the subset of the graph by banker's sequence. Void generate (INT flag [], int position, int positions) {If (finish) return; If (position <positions) {If (position = 0) {for (INT I = 0; I <edge. size (); I ++) {flag [position] = I; generate (flag, Position + 1, positions );}} else {for (INT I = Flag [position-1] + 1; I <edge. size (); I ++) {flag [position] = I; generate (flag, Position + 1, positions) ;}} elsecheck (flag, position );} // enumerate the subset of the graph vector to determine whether it is a dominant set. Void enumerating_subset () {for (INT I = 1; I <= edge. size (); I ++) {int * flag = new int [edge. size ()]; generate (flag, 0, I); Delete [] flag; If (finish) return ;}} bool CMP (lluint X, lluint y) {return x> Y;} // obtain the number of vertices (mdsn) of the smallest governing set of the graph ). Int mdsn (vector <int> & vertex) {int base = 0; origin_tag = 0; target_tag = 0; vector <bool> dirty (vertex. size (); fill (dirty. begin (), dirty. end (), false); // The point with a clearance degree of 0. If there is no path between a vertex with a degree of 0 and other vertices, the minimum dominance set of the graph must include // The vertex. It indicates that the base variable of the number of vertices in the minimum governing set needs to be increased by 1. For (INT I = 0; I <vertex. size (); I ++) {If (vertex [I]. size () = 0) {base ++; origin_tag | = (lluint) 1 <I) ;}if (vertex [I]. size () = 1 & dirty [I] = false) {dirty [I] = true; if (dirty [vertex [I] [0]-1] = false) {base ++; dirty [vertex [I] [0]-1] = true ;}} target_tag | = (lluint) 1 <I) ;}// point with a clearance degree of 1. A point with a degree of 1 indicates that vertex A is connected only to the other vertex B, then the vertex B can be included in the minimum control set. Edge. clear (); For (INT I = 0; I <vertex. size (); I ++) {If (dirty [I] = true) {origin_tag | = (lluint) 1 <I); For (Int J = 0; j <vertex [I]. size (); j ++) origin_tag | = (lluint) 1 <(vertex [I] [J]-1 ));} if (dirty [I] = false & vertex [I]. size ()> 0) {lluint t = (lluint) 1 <I); For (Int J = 0; j <vertex [I]. size (); j ++) T | = (lluint) 1 <(vertex [I] [J]-1); edge. push_back (t) ;}/// sort. When the degree is high, consider it first. Sort (edge. begin (), edge. end (), CMP); Minimum = 0; finish = false; enumerating_subset (); Return (base + minimum);} int servicing_stations (vector <int> & vertex) {// use the width to search for the separated subgraph first, and calculate the number of vertices in the smallest Dominant Set of the subgraph. The addition of the phase // indicates the number of vertices in the minimum Dominant Set of the source image. Int Total = 0; while (vertex. size ()> 0) {vector <int> open; set <int> close; int size = 0; open. push_back (vertex [0]); close. insert (vertex [0] [0]); vertex. erase (vertex. begin (); While (open. size ()> size) {int origin = size; int current = open. size ()-1; size = open. size (); For (INT I = origin; I <= current; I ++) {for (Int J = 1; j <open [I]. size (); j ++) {If (close. find (open [I] [J]) = close. end ()) {Close. insert (open [I] [J]); For (INT m = 0; m <vertex. size (); m ++) {If (vertex [m] [0] = open [I] [J]) {open. push_back (vertex [m]); vertex. erase (vertex. begin () + M); break ;}}}}// adjust the serial number of the separated subgraph for subsequent operations. Vector <vector <int> TMP; For (INT c = 1; C <= max_town; C ++) if (close. Find (c )! = Close. end () {for (INT I = 0; I <open. size (); I ++) if (open [I] [0] = C) TMP. push_back (open [I]);} For (INT I = 0; I <TMP. size (); I ++) {int current = TMP [I] [0]; for (INT m = 0; m <TMP. size (); m ++) for (INT n = 1; n <TMP [M]. size (); N ++) if (TMP [m] [N] = Current) TMP [m] [N] = (I + 1 );} for (INT I = 0; I <TMP. size (); I ++) TMP [I]. erase (TMP [I]. begin (); // calculates the minimum number of vertices in the parent set of the subgraph. Total + = mdsn (TMP);} return total;} int main (int ac, char * AV []) {int N; int m; int X, Y; vector <vector <int> vertex; while (CIN> N> M, N & M) {vertex. clear (); vertex. resize (n); // The number of the first vertex in the array. For (INT I = 0; I <n; I ++) vertex [I]. push_back (I + 1); // read the path between towns. For (INT I = 0; I <m; I ++) {// do not add a path for self-connection. Cin> x> Y; If (X! = Y) {vertex [X-1]. push_back (y); vertex [Y-1]. push_back (x) ;}} cout <servicing_stations (vertex) <Endl ;}return 0 ;}
Reprinted from: http://blog.csdn.net/metaphysis/article/details/6601365
Version 2
1.225 MSAC.
N points and M relationships are given. A service station can be placed at any point. If a service station is placed at this point, the points connected to it can be served, ask the minimum number of service stations so that all points can be served.
Solution: The idea is very simple. The key is to use DFS to collect data. My main optimization lies in two aspects.
First, start DFS by the DoT number. cur indicates the current access point.
<1> each point is nothing more than put or not put (note that we cannot simply judge whether the point should be put in the service station based on whether it is covered or not)
<2> the first pruning. If the number of covered points does not increase after the service station is added, it can be determined that the current vertex is not put (it is the same as the put case. Why should we add another vertex)
<3> for the second pruning, this route is cut off when the number of service stations is greater than the minimum value calculated previously.
<4> In the third pruning, when the previous vertex cannot be overwritten, You can terminate the seek.
Here, I want to explain the third pruning result. For example, I have accessed 5th vertices, but 1 is not covered yet, and 2 is related to 1 <5, note 2 has been visited, indicating that neither 1 nor 2 has been deployed at the service station, and the rest of N points have been put and do not affect the coverage status of less than 1, therefore, this path cannot be met.
I am going to ask a small Optimization for optimization 3. If we follow the normal idea, we need to open an array to record which points are placed at the service station, then, when optimizing 3, you need to traverse the judgment point to determine whether all the related points of the judgment point have been considered. However, I have to sort the vertices in order to compare the largest vertices with the currently accessed vertices. If the vertices are greater than the vertices, they are not determined yet.
# Include <stdio. h> # include <string. h >#include <algorithm> using namespace STD; # define n 40int n, m, Min, REC [N]; int G [N] [N], son [N]; int CMP (const Int & A, const Int & B) {return A> B;} void DFS (INT cur, int CNT, int sum) {If (sum> = min) // pruning 2: when the number of stations placed exceeds the minimum value calculated above. Return; If (CNT = N) min = sum; For (INT I = 1; I <cur; I ++) // pruning 3: if the vertices that have already been traversed cannot be overwritten, it is useless to continue to collect the cable. If (! REC [I] & G [I] [0] <cur) return; DFS (cur + 1, CNT, sum); int K = 0, vis [N]; for (INT I = 0; I <son [cur]; I ++) if (REC [G [cur] [I] = 0) {vis [k ++] = G [cur] [I]; REC [G [cur] [I] = 1;} If (! K) // pruning 1: increase the coverage point to 0. Return; DFS (cur + 1, CNT + k, sum + 1); For (INT I = 0; I <K; I ++) // trace to restore the vertex, otherwise, the answer will be wrong. REC [vis [I] = 0;} int main () {int A, B; while (scanf ("% d", & N, & M ), N + M) {// Init; memset (G, 0, sizeof (g); memset (son, 0, sizeof (son); memset (REC, 0, sizeof (REC); min = n + 1; // read; For (INT I = 0; I <m; I ++) {scanf ("% d", & A, & B); G [a] [son [a] ++] = B; G [B] [son [B] ++] = A ;}// handle; For (INT I = 1; I <= N; I ++) {G [I] [son [I] ++] = I; sort (G [I], G [I] + son [I], CMP ); // For details about optimization 3, refer to the explanation .} DFS (1, 0, 0); printf ("% d \ n", min);} return 0 ;}
Reprinted from: Click to open the link