首页 > 代码库 > HDU 1882 Strange Billboard(位运算)

HDU 1882 Strange Billboard(位运算)

题目链接

题意 : 给你一个矩阵,有黑有白,翻转一个块可以让上下左右都翻转过来,问最少翻转多少次能让矩阵变为全白。

思路 : 我们从第一行开始枚举要翻转的状态,最多可以枚举到2的16次方,因为你只要第一行的确定了,第二行要翻转的也就确定了,所以第一行的状态决定了最后的状态。看了网上大神,真是让位运算废了啊,,,,,太复杂了。。。。。。

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <map>
 5 
 6 using namespace std;
 7 
 8 const int INF = 999999999 ;
 9 int r,c,n;
10 int data[17] ;
11 
12 void Init()
13 {
14     char mapp[17][17] ;
15     memset(data,0,sizeof(data)) ;
16     if(r >= c)
17     {
18         for(int i = 0 ; i < r ; i++)//每一行都用一个二进制数来保存
19         {
20             data[i] = 0 ;
21             scanf("%s",mapp[i]) ;
22             for(int j = 0 ; j < c ; j++)
23             {
24                 if(mapp[i][j] == X)
25                     data[i] |= 1 << j ;//这一行中将是X的地方全部存为1
26             }
27         }
28     }
29     else//优化,当列比较少的时候就翻转过来用列。
30     {
31         for(int i = 0 ; i < r ; i++)
32         {
33             data[i] = 0 ;
34             scanf("%s",mapp[i]) ;
35             for(int j = 0 ; j < c ; j++)
36                 if(mapp[i][j] == X)
37                     data[j] |= 1 << i ;
38         }
39         //把r和c的两值互换
40         r = r^c ;
41         c = r^c ;
42         r = r^c ;
43     }
44 }
45 void solve()
46 {
47     int minn = INF ;
48     int a[17],tmp[17] ;
49     for(int i = 0 ; i < (1 << c) ; i++)//枚举状态,共有2的c次方个
50     {
51         for(int j = 0 ; j < r ; j++)
52             a[j] = data[j] ;
53         for(int j = 0 ; j < r ; j++)
54         {
55             tmp[j] = j == 0 ? i : a[j-1] ;
56             a[j] ^= tmp[j] ;//本行要翻转
57             a[j] ^= tmp[j] >> 1 ;//右边也要翻转
58             a[j] ^= tmp[j] << 1 & ((1 << c)-1) ;//防止最左边的那位超出范围
59             a[j+1] ^= tmp[j] ;//下一行也要翻转
60         }
61         if(!a[r-1])//因为第一行确定之后第二行也就确定了,以此类推,只要判断最后一行是不是全白就行了
62         {
63             int cnt = 0 ;
64             for(int j = 0 ; j < r ; j++)
65             {
66                 for(int k = tmp[j] ; k > 0 ; k >>= 1)
67                     if(1 & k) cnt ++ ;
68             }
69             if(cnt < minn) minn = cnt ;
70         }
71     }
72     if(minn == INF)
73         printf("Damaged billboard.\n") ;
74     else printf("You have to tap %d tiles.\n",minn) ;
75 }
76 int main()
77 {
78     while(~scanf("%d %d",&r,&c))
79     {
80         if(r == 0 && c == 0)
81             break ;
82         Init() ;
83         solve() ;
84     }
85     return 0;
86 }
View Code

 

如果那四行看不懂,没关系,因为我也看不太懂,看这里应该比较好理解一点,就是翻本行,翻左边那一列,右边那一列,下一行