11825-hackers' crackdown state compression DP enumeration subset
ACM
Address: 11825-hackers' crackdown
Question:
There is ~ N-1 computers constitute a network of n-1 computers. There are N services in total, and all services are running on each computer. For each computer, you can choose to stop a service, this behavior will cause the services on this computer and other computers connected to it to stop (the services that have been stopped will continue to stop ). How many services can be paralyzed (that is, no computer is running this service ).
Analysis:
To put it bluntly, it is:
Put N sets P [I],0<=i<nGroups into multiple groups as much as possible, so that the aggregation of each set in each group is the complete set.
Status compression is used to record the services running on each node. Because the data size is 16, a set can be expressed with numbers in the int range.
After preprocessing, cover and process each set composed of 16 nodes will bring great service effects.
Then DP, if cover [S0] = All (all is 1), then the part of s ^ S0 may also terminate the service,dp[S] = max(dp[S], dp[S^S0]+1).
I have referred to the messy question, so I want to understand the question of enumeration subsets.
Enumeration subset template:
// For the set S
For (INT S0 = s; S0; S0 = S & (S0-1) // enumerate S0 as a subset
...
Principle:S&(S0 - 1)In fact, it is the result of ignoring all 0 in S and decreasing 1 continuously.
Code:
/** Author: illuz <iilluzen[at]gmail.com>* File: 11825.cpp* Create Date: 2014-06-27 20:43:48* Descripton: sub set/ dp/ numeric */#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N = 16;int n, m, t, mask[N], cover[1<<N], dp[1<<N], tot;int main() {int cas = 0;while (~scanf("%d", &n) && n) {// inputfor (int i = 0; i < n; i++) {scanf("%d", &m);mask[i] = (1 << i);while (m--) {scanf("%d", &t);mask[i] |= (1 << t);}}// get the union set of coverfor (int S = 0; S < (1 << n); S++) {cover[S] = 0;for (int i = 0; i < n; i++) {if (S & (1 << i)) {cover[S] |= mask[i];}}}// dpdp[0] = 0;tot = (1 << n) - 1;for (int S = 1; S < (1 << n); S++) {dp[S] = 0;for (int S0 = S; S0; S0 = (S0 - 1)&S) {if (cover[S0] == tot) {dp[S] = max(dp[S], dp[S^S0] + 1);}}}printf("Case %d: %d\n", ++cas, dp[tot]);}return 0;}