HDU 4770 Lights Against Dudely(二进制枚举子集)

题目中有一个重要提示: 脆弱的房间最多只有15个,而且灯只能放在脆弱的房间(否则一定会照到坚固房间),而且一个房间只能放一个灯,所以枚举所有子集就行了O(2^15)。

一开始没看清题意,以为所有的灯都可以任意朝向,后来才知道只有一个灯可以任意朝向。   所以我们再枚举那个灯是特殊的灯就行了。总复杂度O(15*2^15),可以接受。

细节参见代码:

#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
const int INF = 10000000;
const int maxn = 205;
int n,m,maxd,vis[maxn][maxn],cnt;
struct node{
    int x,y;
    node(int x=0, int y=0) : x(x), y(y) {}
    bool operator < (const node& rhs) const {
        return x < rhs.x || (x == rhs.x && y < rhs.y);
    }
}a[maxn];
char s[maxn][maxn];
map<node,int> p,pp;
int main() {
    while(~scanf("%d%d",&n,&m)) {
        if(!n && !m) return 0;
        for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
        cnt = 0;
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=m;j++) {
                if(s[i][j] == '.') {
                    a[cnt++] = node(i,j);
                }
            }
        }
        int ans = INF;
        if(cnt == 0) { printf("0\n"); continue; }
        for(int i=0;i<cnt;i++) {
            for(int S=0;S<(1<<cnt);S++) {
                if(S & (1<<i)) ; else continue;
                int cur = 0, c = 0;
                for(int j=0;j<cnt;j++) if(S & (1<<j)) cur++;
                bool ok = true;
                p.clear(); pp.clear();
                for(int j=0;j<cnt;j++) { //放置其他灯
                    if(i == j) continue;
                    if(S & (1<<j)) {
                        node u = a[j];
                        if(!p.count(u)) { p[u] = 1; c++; }
                        if(u.x > 1) {
                            if(s[u.x-1][u.y] == '#') { ok = false; break; }
                            else {
                                if(!p.count(node(u.x-1,u.y))) { p[node(u.x-1,u.y)] = 1; c++; }
                            }
                        }
                        if(u.y < m) {
                            if(s[u.x][u.y+1] == '#') { ok = false; break; }
                            else {
                                if(!p.count(node(u.x,u.y+1))) { p[node(u.x,u.y+1)] = 1; c++; }
                            }
                        }
                    }
                }
                if(!ok) continue; //放置特殊的灯的四种朝向,第一种
                node u = a[i];
                if(!p.count(u)) { p[u] = 1; c++; }
                int cc = c;  pp = p;
                if(u.x > 1) {
                    if(s[u.x-1][u.y] == '#') ok = false;
                    else {
                        if(!p.count(node(u.x-1,u.y))) { p[node(u.x-1,u.y)] = 1; c++; }
                    }
                }
                if(u.y < m) {
                    if(s[u.x][u.y+1] == '#') ok = false;
                    else {
                        if(!p.count(node(u.x,u.y+1))) { p[node(u.x,u.y+1)] = 1; c++; }
                    }
                }
                if(ok && c == cnt) ans = min(ans,cur);
                /第二种
                p = pp; c = cc; ok = true;
                if(u.x < n) {
                    if(s[u.x+1][u.y] == '#') ok = false;
                    else {
                        if(!p.count(node(u.x+1,u.y))) { p[node(u.x+1,u.y)] = 1; c++; }
                    }
                }
                if(u.y < m) {
                    if(s[u.x][u.y+1] == '#') ok = false;
                    else {
                        if(!p.count(node(u.x,u.y+1))) { p[node(u.x,u.y+1)] = 1; c++; }
                    }
                }
                if(ok && c == cnt) ans = min(ans,cur);
                第三种
                p = pp; c = cc; ok = true;
                if(u.x > 1) {
                    if(s[u.x-1][u.y] == '#') ok = false;
                    else {
                        if(!p.count(node(u.x-1,u.y))) { p[node(u.x-1,u.y)] = 1; c++; }
                    }
                }
                if(u.y > 1) {
                    if(s[u.x][u.y-1] == '#') ok = false;
                    else {
                        if(!p.count(node(u.x,u.y-1))) { p[node(u.x,u.y-1)] = 1; c++; }
                    }
                }
                if(ok && c == cnt) ans = min(ans,cur);
                /第四种
                p = pp; c = cc; ok = true;
                if(u.x < n) {
                    if(s[u.x+1][u.y] == '#') ok = false;
                    else {
                        if(!p.count(node(u.x+1,u.y))) { p[node(u.x+1,u.y)] = 1; c++; }
                    }
                }
                if(u.y > 1) {
                    if(s[u.x][u.y-1] == '#') ok = false;
                    else {
                        if(!p.count(node(u.x,u.y-1))) { p[node(u.x,u.y-1)] = 1; c++; }
                    }
                }
                if(ok && c == cnt) ans = min(ans,cur);
            }
        }
        if(ans == INF) printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值