hdu1045 Fire Net---二进制枚举子集

题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1045

题目大意:

给你一幅n*n的图,再给你一些点,这些点的上下左右不能再放其他点,除非有墙(‘X’)隔着,问最多可以放多少个这样的点。

思路:

由于n不大于4,最多16个点,想到可以二进制枚举子集,然后逐个判断每个子集的可行性。

 1 #include<iostream>
 2 #include<string>
 3 #include<vector>
 4 #include<cstdio>
 5 #include<cstring>
 6 #define FOR(i, a, b) for(int i = a; i < b; i++)
 7 using namespace std;
 8 int n, k;
 9 char a[10][10];
10 int dir[4][2] = {1,0,0,1,-1,0,0,-1};
11 bool judge(int x)
12 {
13     char b[10][10];
14     int c[20], tot = 0;
15     memcpy(b, a, sizeof(a));
16     for(int i = 0; i < n * n; i++)
17     {
18         if(x & (1 << i))
19         {
20             int xx = i / n;
21             int yy = i % n;
22             if(b[xx][yy] == 'X')return false;//剪枝,如果子集覆盖了墙,直接返回假 
23             b[xx][yy] = 'a';
24             c[tot++] = i;
25         }
26     }
27     for(int i = 0; i < tot; i++)//从每个点出发 
28     {
29         int x = c[i] / n;
30         int y = c[i] % n;
31         for(int i = 0; i < 4; i++)//四个方向遍历 
32         {
33             int xx = x + dir[i][0];
34             int yy = y + dir[i][1];
35             while(xx >= 0 && xx < n && yy >= 0 && yy < n)//控制边界 
36             {
37                 if(b[xx][yy] == 'X')break;//碰到墙跳出循环 
38                 if(b[xx][yy] == 'a')return false;//碰到另一个'a'说明有误 
39                 xx += dir[i][0];//继续往这方向遍历 
40                 yy += dir[i][1];
41             }
42         }
43     }
44     return true;
45 }
46 int f(int x)//返回子集中的size 
47 {
48     int tot = 0;
49     for(int i = 0; i < (n * n); i++)
50     {
51         if(x & (1 << i))tot++;
52     }
53     return tot;
54 }
55 int main()
56 {    
57     while(cin >> n && n)
58     {
59         int ans = 0;
60         for(int i = 0; i < n; i++)cin >> a[i];
61         for(int i = 0; i < (1 << (n * n)); i++)
62         {
63             if(judge(i))ans = max(ans, f(i));//更新最优解 
64         }
65         cout << ans << endl;
66     }
67     return 0;
68 }

 听说可以用贪心或者二分图解决,以后学到这里再来更新

转载于:https://www.cnblogs.com/fzl194/p/8674823.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值