UVA 10572 Black and White(插头DP)

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1513

题意:给出一个n*m的格子,有些已经染成黑色,有些已经染成白色,有些还没有染色。将未染色的染成黑色或者白色使得所有相同颜色的组成一个连通块且不存在同颜色的2*2的区域。有多少种染色方法?输出其中一种。

思路:一、首先,需要解决的是不存在2*2的区域和黑白两种颜色只能各自形成一个连通块两件事情。状态记录轮廓线的连通性,以及轮廓线上的m个格子的颜色以及左上角的颜色的格子。设上面、左侧以及左上的格子的颜色分别为U、L、LU,当前格子的颜色为col(枚举为黑或者白)。那么只要col=L=U=LU那么这个转移就是不合法的,直接舍弃。这样就解决了不存在2*2相同的。然后就是解决每种颜色只形成一个连通块。其实就是在考虑当前的格子放置为col颜色之后会不会使得另一种颜色出现孤立的块(col颜色的只要以后合法是不会出现孤立的,所以当前只用考虑另一种颜色的会不会被孤立)。那么假设当前为col时出现的另一种颜色(设为COL)的孤立,那么U=COL,且轮廓线上只有这一个地方是U所在连通块(否则就不会孤立)且(1)轮廓线上COL颜色的不止一个(那么其他COL颜色所在的块肯定跟U不是一个,且U被当前的分隔开了);(2)COL颜色只有U这一个,那么当前位置只能是[n-1,m-2]或者[n-1,m-1](范围是[0,0]到[n-1,m-1])。另外,对于最后一个格子(n-1,m-1)需要特判,不能出现LU=col但是L和U都不等于col。

二、路径的记录。可以使用比如pre[i][j][k]表示当前点(i,j)是由(i,j-1)的k状态转移来的。

#include <iostream>

#include <cstdio>

#include <string.h>

#include <algorithm>

#include <cmath>

#include <vector>

#include <queue>

#include <set>

#include <stack>

#include <string>

#include <map>





#define max(x,y) ((x)>(y)?(x):(y))

#define min(x,y) ((x)<(y)?(x):(y))

#define abs(x) ((x)>=0?(x):-(x))

#define i64 long long

#define u32 unsigned int

#define u64 unsigned long long

#define clr(x,y) memset(x,y,sizeof(x))

#define CLR(x) x.clear()

#define ph(x) push(x)

#define pb(x) push_back(x)

#define Len(x) x.length()

#define SZ(x) x.size()

#define PI acos(-1.0)

#define sqr(x) ((x)*(x))



#define FOR0(i,x) for(i=0;i<x;i++)

#define FOR1(i,x) for(i=1;i<=x;i++)

#define FOR(i,a,b) for(i=a;i<=b;i++)

#define FORL0(i,a) for(i=a;i>=0;i--)

#define FORL1(i,a) for(i=a;i>=1;i--)

#define FORL(i,a,b)for(i=a;i>=b;i--)





#define rush() int CC; for(scanf("%d",&CC);CC--;)

#define Rush(n)  while(scanf("%d",&n)!=-1)

#define Rush(n,m)  while(scanf("%d%d",&n,&m)!=-1)

using namespace std;





void RD(int &x){scanf("%d",&x);}

void RD(i64 &x){scanf("%lld",&x);}

void RD(u32 &x){scanf("%u",&x);}

void RD(double &x){scanf("%lf",&x);}

void RD(int &x,int &y){scanf("%d%d",&x,&y);}

void RD(u32 &x,u32 &y){scanf("%u%u",&x,&y);}

void RD(double &x,double &y){scanf("%lf%lf",&x,&y);}

void RD(int &x,int &y,int &z){scanf("%d%d%d",&x,&y,&z);}

void RD(u32 &x,u32 &y,u32 &z){scanf("%u%u%u",&x,&y,&z);}

void RD(double &x,double &y,double &z){scanf("%lf%lf%lf",&x,&y,&z);}

void RD(char &x){x=getchar();}

void RD(char *s){scanf("%s",s);}

void RD(string &s){cin>>s;}



void PR(int x) {printf("%d\n",x);}

void PR(i64 x) {printf("%lld\n",x);}

void PR(u32 x) {printf("%u\n",x);}

void PR(double x) {printf("%.4lf\n",x);}

void PR(char x) {printf("%c\n",x);}

void PR(char *x) {printf("%s\n",x);}

void PR(string x) {cout<<x<<endl;}





const int INF=1000000000;

const int HASHSIZE=30007;

const int N=200005;



int n,m,code[15],cur,pre,sx,sy;

char s[15][15],op[70][N];

int Pre[70][N];

int ans;



struct node

{

    int e,next[N],head[HASHSIZE];

    int cnt[N],state[N],colState[N];



    void init()

    {

        clr(head,-1);

        e=0;

    }







    void push(int st,int colSt,int val,int id,int k,char opChar)

    {

        int i,x=((st<<6)+colSt)%HASHSIZE;

        for(i=head[x];i!=-1;i=next[i])

        {

            if(state[i]==st&&colState[i]==colSt)

            {

                cnt[i]+=val;

                return;

            }

        }

        state[e]=st; colState[e]=colSt; cnt[e]=val;

        Pre[id][e]=k; op[id][e]=opChar;

        next[e]=head[x];

        head[x]=e++;

    }

};





node dp[2];





void decode(int code[],int m,int st)

{

    int i;

    FORL0(i,m-1) code[i]=st&7,st>>=3;

}



void trans(int x,int y)

{

    int i;

    FOR0(i,m) if(code[i]==x) code[i]=y;

}



int encode(int code[],int m)

{

    int ans=0;

    int hash[15],i,cnt=0;

    clr(hash,-1);

    FOR0(i,m)

    {

        if(hash[code[i]]==-1) hash[code[i]]=cnt++;

        code[i]=hash[code[i]];

        ans=(ans<<3)|code[i];

    }

    return ans;

}



void update1(int i,int j,int col)

{

    int x,y,k,t;

    int L,U,LU,colSt;

    FOR0(k,dp[pre].e)

    {

        colSt=dp[pre].colState[k];

        L=j?((colSt>>(j-1))&1)==col:0;

        U=i?((colSt>>j)&1)==col:0;

        LU=col==(colSt>>m);

        if(L&&U&&LU) continue;

        if(i==n-1&&j==m-1&&!L&&!U&&LU) continue;

        decode(code,m,dp[pre].state[k]);

        if(i&&!U)

        {

            x=y=0;

            FOR0(t,m)

            {

                if(code[t]==code[j]) x++;

                if((colSt>>t&1)!=col) y++;

            }

            if(x==1)

            {

                if(y>1) continue;

                if(i<n-1||j<m-2) continue;

            }

        }

        x=code[j-1];

        y=code[j];

        if(L&&U)

        {

            if(x!=y) trans(y,x);

        }

        else if(!U&&L) code[j]=code[j-1];

        else if(!U&&!L) code[j]=m;



        if(colSt&(1<<j)) colSt|=(1<<m);

        else colSt&=~(1<<m);



        if(col) colSt|=(1<<j);

        else colSt&=~(1<<j);



        dp[cur].push(encode(code,m),colSt,dp[pre].cnt[k],i*m+j,k,col?'#':'o');

    }

}





void print(int k)

{

    int i,j;

    FORL0(i,n-1) FORL0(j,m-1)

    {

        s[i][j]=op[i*m+j][k];

        k=Pre[i*m+j][k];

    }

    FOR0(i,n) s[i][m]=0,puts(s[i]);

}





void DP()

{

    pre=0,cur=1;

    dp[0].init(); dp[0].push(0,0,1,0,0,0);

    int i,j,k;

    FOR0(i,n) FOR0(j,m)

    {

        dp[cur].init();

        if(s[i][j]!='#') update1(i,j,0);

        if(s[i][j]!='o') update1(i,j,1);

        pre^=1;

        cur^=1;

    }

    ans=0;

    FOR0(i,dp[pre].e)

    {

        decode(code,m,dp[pre].state[i]);

        FOR0(j,m) if(code[j]>1) break;

        if(j==m) ans+=dp[pre].cnt[i],k=i;

    }

    PR(ans);

    if(ans) print(k);

    puts("");

}



int main()

{

    rush()

    {

        RD(n,m);

        int i,j;

        FOR0(i,n) RD(s[i]);

        DP();

    }

    return 0;

}

  

你可能感兴趣的:(uva)