NOJ2214题目解题笔记

来源:互联网 发布:知乎和知网 编辑:程序博客网 时间:2024/06/03 16:17

原题链接:http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=2214

比赛描述

MiaoMiao和Bird喜欢一起看电视,他们都有一些近视。

有次他们看电视的时候,Bird的眼镜一不小心掉到地上,这下Bird看到电视画面都变模糊了。确切来说,我们把电视上的像素分成两种,用.表示空白区域,用*表示有颜色区域。

电视的画面为n*m的像素矩阵,对于每一个MiaoMiao看到的有色像素*,Bird都会看成

.*.

***

.*.

模糊的方块会相互重叠,可能会使原本空白区域看起来像有颜色的区域。

现在给出Bird看到的电视画面,请你求出MiaoMiao看到的电视画面中有颜色像素的最小值。




输入

第一行两个正整数n(1 ≤ n ≤ 8)和m(1 ≤ m ≤ 8)

接下来有n行,每一行有m个字符('.'或'*')。


输出

输出一个整数,表示MiaoMiao可能看到的有颜色像素数量的最小值,如果Bird看到的情况不存在,则输出-1。

样例输入

3 3
.*.
***
.*.

样例输出

1

题目来源

MoliH


动态规划。

我没有找到什么高效的解法,复杂度n*4^m(如果m>n,可以把整个电视屏幕转置,变成m*4^n),但是所幸n,m都很小。

首先对于每一行每个点是否有像素点的选择会受到上一行的影响。

int flagarray[]记录每个点上一行对应点情况。

flagarray[i]=0 上一行i处为空  

flagarray[i]=1上一行i处看到是像素点并且周围没有真正的像素点 

flagarray[i]=2上一行i处看到是像素点并且周围有真正的像素点  

flagarray[i]=3上一行i处为真正像素点

当flagarray[i]=1,那么这一行的i处必须为真正的像素点,否则,上一行i处看到的就是空白了。

当flagarray[i]=0,那么这一行的i处必须不为真正的像素点,否则,上一行i处看到的就是像素点了。

当flagarray[i]=2,这一行i出可以有真正的像素点。

当flagarray[i]=3,这一行i处以及周围可以不必在放置真正像素点。

当第i行的flagarray[]已经确定的情况下,那么从第i行到最后一行的所有结果已经是一个确定值了。

不妨定义dp[i][flag],记录在第i行flagarray下,从i到n-1行的真正像素点数量。(flag=flagarray[0]+flagarray[1]*4+flagarray[2]*4^2+...)

每一行flag的所有可能性最多为4^m,n行一共n*4^m。

以下为代码

#include <iostream>#include <stdio.h>#include <algorithm>#include <stdlib.h>#include <string.h>#include <queue>#include <math.h>using namespace std;int p[8][8];int dp[8][65536];int n;int m;int m2;int ercifang[]= {1,2,4,8,16,32,64,128};//#define debug 0int get1s(int value){    int res=0;    while(value)    {        if(value&1)            res++;        value>>=1;    }    return res;}//flagarray[i] 0 上一行i处为空  1上一行i处为未覆盖点 2上一行i处为覆盖点 3上一行i处为像素中心点int testvalueflag(int line,int value,int flagarray[]){    for(int i=0; i<m; i++)    {        if(flagarray[i]==0&&(value&ercifang[i]))            return 0;        if(flagarray[i]==1&&((value&ercifang[i])==0))            return 0;        if(p[line][i]==0)        {            if(i>=1&&(value&ercifang[i-1]))                return 0;            if(i<m-1&&(value&ercifang[i+1]))                return 0;            if(value&ercifang[i])                return 0;            if(flagarray[i]==3)                return 0;        }        else  if(line==n-1)        {            if(i>=1&&(value&ercifang[i-1]))                continue;            if(i<m-1&&(value&ercifang[i+1]))                continue;            if(value&ercifang[i])                continue;            if(flagarray[i]==3)                continue;            return 0;        }    }    return 1;}int run(int line,int flag){    if(dp[line][flag]>=0)        return dp[line][flag];    int res=1000000;#ifdef debug    int lastvaluearray[8];#endif    int flagarray[8];    int flagcopy=flag;    memset(flagarray,0,8*sizeof(int));    for(int i=0; i<8; i++)    {        flagarray[i]=flagcopy&3;        flagcopy>>=2;    }    for(int value=0; value<m2; value++)    {        if(testvalueflag(line,value,flagarray))        {            int rest;            if(line==n-1)                rest=0;            else            {                int nextflagarraay[8];                memset(nextflagarraay,0,8*sizeof(int));                //flag 0 上一行此处为空  1上一行此处为未覆盖点 2上一行此处为覆盖点 3上一行此处为像素中心点                for(int i=0; i<m; i++)                {                    if(p[line][i]==0)                        nextflagarraay[i]=0;                    else                    {                        if(value&ercifang[i])                            nextflagarraay[i]=3;                        else if(flagarray[i]==3)                            nextflagarraay[i]=2;                        else if(i>=1&&(value&ercifang[i-1]))                            nextflagarraay[i]=2;                        else if(i<m-1&&(value&ercifang[i+1]))                            nextflagarraay[i]=2;                        else nextflagarraay[i]=1;                    }                }                int nextflag=0;                for(int i=m-1; i>=0; i--)                {                    nextflag<<=2;                    nextflag|=nextflagarraay[i];                }                rest=run(line+1,nextflag);            }            int thisline=get1s(value);            if(res>rest+thisline)            {#ifdef debug                int valuecopy=value;                memset(lastvaluearray,0,8*sizeof(int));                for(int i=0; i<8; i++)                {                    lastvaluearray[i]=valuecopy%2;                    valuecopy/=2;                }#endif                res=rest+thisline;            }        }    }    dp[line][flag]=res;#ifdef debug    cout<<"line"<<line<<"\nflag:";    for(int i=0; i<8; i++)        cout<<flagarray[i]<<' ';    cout<<endl;    cout<<"value";    for(int i=0; i<8; i++)        cout<<lastvaluearray[i]<<' ';    cout<<endl<<"res"<<res<<endl;#endif    return res;}int main(){#ifdef debug    freopen("in.txt","r",stdin);#endif    cin>>n>>m;    memset(dp,0xff,8*65536*sizeof(int));    for(int i=0; i<n; i++)    {        char str[10];        scanf("%s",str);        for(int j=0; j<m; j++)        {            if(str[j]=='.')                p[i][j]=0;            else                p[i][j]=1;        }    }    if(n<m)    {        for(int i=0; i<8; i++)            for(int j=0; j<i; j++)                swap(p[i][j],p[j][i]);        swap(n,m);    }    m2=pow(2,m);    //43686=2+2*4+2*4^2+...+2*4^7    int ans=run(0,43690);    if(ans>64)        printf("-1");    else        printf("%d",ans);    return 0;}



原创粉丝点击