HDU 4770 Lights Against Dudely 解题报告

39 篇文章 0 订阅

题目

题意:

有矩阵n*m,每个单元是一个房间,有些房间可被照亮有些不能,可被照亮的房间最多15个。在(x,y) 放置灯那么 (x,y+1 )和 (x+1,y)都会被照亮,但是有一盏灯可以转动90或者180或270度。问使得所有可被照亮的房间都被照亮且不可被照亮的房间不被照亮需要的最少的灯,不可能则输出-1.

解法:

可以用状压,枚举哪个房间放灯及灯转动的角度,然后看每个可照亮的房间是否放灯。

代码:

//Time:0ms
//Memory:532KB
//Length:1903B
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 210;
char ma[MAXN][MAXN];
pair<int,int> room[MAXN];
int top=0,ans,bel[MAXN][MAXN];
bool vi[20],tvi[20][20];
int to[4][3][2]={{{0,0},{-1,0},{0,1}},{{0,0},{0,1},{1,0}},{{0,0},{1,0},{0,-1}},{{0,0},{-1,0},{0,-1}}};
inline int cha(int x,int y,int d)
{
    int tx,ty,cnt=0,whi;
    for(int i=0;i<3;++i)
    {
        tx=x+to[d][i][0],ty=y+to[d][i][1];
        if(ma[tx][ty]=='#') cnt=-MAXN;
        if(ma[tx][ty]=='.') whi=bel[tx][ty];
        else    continue;
        cnt+=!vi[whi];
        vi[whi]=1;
    }
    return cnt;
}
void check(int cant,int h,int now,int cnt)
{
    int tmp;
    if(cnt==top)
    {
        ans=min(ans,now);
        return ;
    }
    memcpy(tvi[h],vi,sizeof(vi));
    for(int i=h;i<top&&now<ans;++i)
        if(i!=cant)
        {
            memcpy(vi,tvi[h],sizeof(vi));
            tmp=cha(room[i].first,room[i].second,0);
            if(tmp<0)   continue;
            check(cant,i+1,now+1,cnt+tmp);
        }
    return ;
}
int main()
{
    //freopen("/home/moor/Code/output","r",stdin);
    int n,m;
    while(scanf("%d%d",&n,&m)==2&&n&&m)
    {
        memset(ma,0,sizeof(ma));
        memset(bel,-1,sizeof(bel));
        for(int i=1;i<=n;++i)
            scanf("%s",&ma[i][1]);
        top=0;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
                if(ma[i][j]=='.')
                    bel[i][j]=top,room[top++]=make_pair(i,j);
        ans=MAXN;
        for(int i=0;i<top;++i)
        {
            for(int j=0;j<4;++j)
            {
                memset(vi,0,sizeof(vi));
                int tmp=cha(room[i].first,room[i].second,j);
                if(tmp<0)   continue;
                check(i,0,1,tmp);
            }
            //printf("%d\n",ans);
        }
        if(top==0)  ans=0;
        printf("%d\n",ans<MAXN?ans:-1);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值