Codeforces Gym101246C:Explode 'Em All(DP + bitset)
http://codeforces.com/gym/101246/problem/C
题意:给出一个n*m的图,“*”表示这个地方需要炸掉,炸弹可以如果丢在(i,j)位置的话,那么可以炸掉第i行第j列的所有“*”。问最少需要丢多少个炸弹可以使得所有“*”被炸掉。
思路:一看就以为是个最小顶点覆盖。然后发现做不了。。。
枚举行的状态i,1表示这一行不炸,0表示炸了这一行。
然后递推。
这里用bitset维护行的状态。
f[i][j]表示第i行j列是否有“*”。
dp[i]表示不炸的行状态有哪些列是需要炸的。
num[i]表示不炸的行的数量。
然后每个状态取最优。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define N 25 4 char s[26]; 5 bitset<N> f[N], dp[1<<N]; 6 int id[1<<N], num[1<<N]; 7 8 int lowbit(int x) { return x & -x; } 9 10 int main() { 11 freopen("input.txt", "r", stdin); 12 freopen("output.txt", "w", stdout); 13 int n, m; 14 scanf("%d%d", &n, &m); 15 for(int i = 0; i < n; i++) { 16 scanf("%s", s); 17 for(int j = 0; j < m; j++) { 18 f[i][j] = s[j] == '*'; 19 } 20 } 21 for(int i = 0; i < N; i++) 22 id[1<<i] = i; 23 int ans = max(n, m); 24 for(int i = 1; i < (1 << n); i++) { // 状态i某一位是1表示这一位的行不炸 25 dp[i] = dp[i-lowbit(i)] | f[id[lowbit(i)]]; // 状态i表示行的状态,1表示有'*',dp[i]表示没炸的行有多少列是需要炸的 26 num[i] = num[i-lowbit(i)] + 1; // 表示第i个状态不需要炸的行的数量 27 ans = min(ans, max(n - num[i], (int)dp[i].count())); 28 // n - num[i] 表示炸多少行, dp[i].count()表示炸多少列 29 } 30 printf("%d\n", ans); 31 return 0; 32 }