首页 > 代码库 > ZOJ 3306 状压dp
ZOJ 3306 状压dp
转自:http://blog.csdn.net/a497406594/article/details/38442893
In order to celebrate the 8th anniversary of ZOJ, watashi introduces a strange game to other ZJU ACM team members. The board of the game consists of 20X20 grids.
There‘re some monsters in the grid and 40 buttons along the board. Each row and column is controlled by a single button, while each button can be pushed ONLY ONCE.
- If you push a row-controlling button, the health point of all the monsters in the corresponding row will decrease 1.
- If you push a column-controlling button, the health point of all the monsters in the corresponding column will decrease 1.
The health point of each monster is 2 initially, and if the monster‘s health point is 0, we say that the monster has been killed. The goal of the game is to kill as many monsters as possible and you cannot push more than N buttons.
Though Watashi plays the game day and night, he cannot always achieve the perfect goal. Please help him to find the best solution of some specific boards.
Input
The first line of each test case contains the numbers N ( 1 <= N <= 40 ).
Then there‘re 20 lines, each with 20 characters. The jth character in the ith line correspond to the state in grid (i, j). ‘.‘ for the empty grid, ‘#‘ for a monster.
The input will contain no more than 10 test cases.
The last test case is followed by one zero.
Output
For each test case output one number, the maximum number of dead monsters.
Sample Input
3..........................................###...................................................................................................................................................................................................................................................................................................................................................................10################################################################################################################################################################################################################################################################################################################################################################################################################0
Sample Output
225
题意:每次给出一张20*20的图,#表示拥有两滴血的怪物,有两种减怪物血的方式,一种是整列减1滴血,另一种是整行减1滴血,且每行每列只能减一次。提供n次,问最多能杀掉多少怪物。
思路:主要还是围绕着消除哪些行跟哪些列,并使行+列=n,这样很容易就相当枚举其中一个,行不容易处理,反而列可以用状压dp进行处理。用1表示选取了当前列。接下来只要选取所在列下,对能每行能消除的个数进行排序,选取最多能消除的前几行。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<map> 9 #include<vector> 10 11 #define N 25 12 #define M 15 13 #define mod 1000000007 14 #define mod2 100000000 15 #define ll long long 16 #define maxi(a,b) (a)>(b)? (a) : (b) 17 #define mini(a,b) (a)<(b)? (a) : (b) 18 19 using namespace std; 20 21 int n; 22 char s[N][N]; 23 int have[N]; 24 int ma; 25 int tot; 26 int cou[N]; 27 int cc[(1<<20)+10]; 28 int now; 29 30 void ini1() 31 { 32 memset(cc,0,sizeof(cc)); 33 for(int i=0;i<(1<<20);i++) 34 { 35 int cnt=0; 36 for(int j=0;j<20;j++) 37 if(i&(1<<j)) 38 cnt++; 39 cc[i]=cnt; 40 } 41 } 42 43 void ini() 44 { 45 int i,j; 46 ma=0; 47 memset(have,0,sizeof(have)); 48 for(i=0;i<20;i++){ 49 scanf("%s",s[i]); 50 } 51 for( i=0;i<20;i++) 52 for( j=0;j<20;j++) 53 if(s[i][j]==‘#‘) 54 have[i]+=(1<<j); 55 56 } 57 58 bool cmp(int i,int j) 59 { 60 return i>j; 61 } 62 63 void solve() 64 { 65 int o,i,j,temp; 66 for(o=1;o<tot;o++) 67 { 68 memset(cou,0,sizeof(cou)); 69 if(cc[o]>n) continue; 70 // printf(" o=%d now=%d\n",o,now); 71 for(i=0;i<20;i++){ 72 cou[i]=cc[ o &have[i] ]; 73 } 74 sort(cou,cou+20,cmp); 75 //for(j=0;j<20;j++) printf(" j=%d cou=%d") 76 temp=0; 77 for(j=0;j<n-cc[o] && j<20;j++){ //注意这里j<20 78 temp+=cou[j]; 79 } 80 ma=max(ma,temp); 81 } 82 } 83 84 int main() 85 { 86 // freopen("data.in","r",stdin); 87 // freopen("data.out","w",stdout); 88 //scanf("%d",&T); 89 // for(int cnt=1;cnt<=T;cnt++) 90 // while(T--) 91 tot=1<<20; 92 ini1(); 93 while(scanf("%d",&n)!=EOF) 94 { 95 if(n==0) break; 96 //printf(" %d\n",n); 97 ini(); 98 solve(); 99 printf("%d\n",ma);100 //cout<<tot<<endl;101 }102 103 return 0;104 }
ZOJ 3306 状压dp