hdu 3935 Dark Room 有n*m的灯,最少几次可以把所有的灯点亮,每次可点周围5个 m<=20

Problem Description
One day Harry Potter came to a magic room, in which there are some shadow monsters sent by the black wizard waiting for him. Fortunately, shadow monsters can only live in areas where there are no lights shining, there are n*m lamps on the roof of the room, every little lamp can only illuminate the scope of the fixed area, and all the area of lights shining don't overlap, some lamps on, some lamps off, the areas below the closed lamps will appear the shadow, and in these areas shadow monsters will attack Harry Potter. Now Harry Potter comes to you and gives you the previous state of the room lights, Harry Potter can control the light switch in a remote place .The state of a light will change as follows: if a lamp state changed, the state of the lights which before it, after it, left to it or right to it will all change. Your task is to calculate how many times we need at least to turn on all the lights by changing the state of the lamps.
 


 

Input
in the first line there are two integers, n (1 < = n < = 100) and m (1 < = m < = 15), stands for there are n lines, each line have m data, 0 stands for the lights off, 1 stands for the lights on.
 


 

Output
for each group of input data, output an integer stands for the minimum number we need to change the state of the lights to put all the lights on, if we can't turn on all the lamps, output 'no solution'.
 


 

Sample Input
  
  
3 3 1 0 1 0 0 0 1 0 1
 


 

Sample Output
  
  
1

 

//

 

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100000;
const int inf=(1<<28);
//有n*m的灯,最少几次可以把所有的灯点亮,每次可点周围5个 m<=20
int g[maxn],x[maxn];
int n,m;
int all;
int ans;
//计算n二进制中1的个数  分治思想  Matrix67博客有讲
int getOnesInN(int n)
{
    n=(n&0x55555555)+((n>>1)&0x55555555);
    n=(n&0x33333333)+((n>>2)&0x33333333);
    n=(n&0x0f0f0f0f)+((n>>4)&0x0f0f0f0f);
    n=(n&0x00ff00ff)+((n>>8)&0x00ff00ff);
    n=(n&0x0000ffff)+((n>>16)&0x0000ffff);
    return n;
}
int main()
{
    while(scanf("%d%d",&n,&m)==2)
    {
        memset(g,0,sizeof(g));
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                //0暗 1亮
                int tmp;scanf("%d",&tmp);
                g[i]=(g[i]<<1)|tmp;
            }
        }
        all=(1<<m)-1;
        ans=inf;
        for(int i=0;i<=all;i++)//枚举第一行开灯情况1,change;0,stay
        {
            for(int j=0;j<n;j++) x[j]=g[j];//用memcpy会超时
            int cnt=getOnesInN(i);//开灯次数
            //press 0 i
            x[0]^=i,x[0]^=i<<1,x[0]^=i>>1;x[0]&=all;
            x[1]^=i;
            //2-n行已经确定
            for(int j=1;j<n;j++)
            {
                int k=x[j-1]^all;//上一行0的位置
                //press j,k
                x[j]^=k,x[j]^=k<<1,x[j]^=k>>1;x[j]&=all;
                x[j+1]^=k;
                //
                cnt+=getOnesInN(k);
            }
            if(x[n-1]==all) ans=min(ans,cnt);
        }
        if(ans==inf)printf("no solution\n");
        else printf("%d\n",ans);
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值