BZOJ 2331 地板(插头DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2331

题意:给出一个n*m的地面。有些是障碍。用L型的地板砖铺满。有多少种方案。

思路:用0表示没有插头,用1表示有插头且可以拐弯,用3表示有插头但是不能再拐弯了。

设有m列,轮廓线为[0,m]。对于格子(i,j),设左插头x上插头y,那么转移有:

(1)x=0,y=0:此时如图1-0,有三种转移,分别是1-1,1-2,1-3;

(2)x!=0,y!=0:此时只有当x=y=1时可以转移,就是合并插头,如图3-0;

(3)x和y中只有一个不是0。不妨设y=0,x!=0,那次此时若x=3,可以延续或者停止;若x=1,可以合并或者可以拐弯。

struct node
{
    int st[N],cnt[N],size;
    int head[HashSize],next[N];

    void init()
    {
        size=0;
        clr(head,-1);
    }

    void add(int S,int x)
    {
        int t=S%HashSize;
        int i;
        for(i=head[t];i!=-1;i=next[i])
        {
            if(st[i]==S)
            {
                cnt[i]=(cnt[i]+x)%mod;
                return;
            }
        }
        st[size]=S;
        cnt[size]=x;
        next[size]=head[t];
        head[t]=size++;
    }
};

node f[2];
int pre,cur;
int n,m;
char s[105][105];

void init()
{
    RD(n,m);
    int i,j;
    FOR1(i,n) RD(s[i]+1);
    char s1[105][105];
    if(m>n)
    {
        FOR1(j,m) FOR1(i,n) s1[j][i]=s[i][j];
        swap(n,m);
        FOR1(i,n) FOR1(j,m) s[i][j]=s1[i][j];
    }
}

int getBit(int st,int k)
{
    return (st>>(k+k))&3;
}

int set0(int st,int k)
{
    return st&(~(3<<(k+k)));
}

int set1(int st,int k)
{
    st=set0(st,k);
    return st|(1<<(k+k));
}

int set3(int st,int k)
{
    return st|(3<<(k+k));
}

void add(int S,int x)
{
    f[cur].add(S,x);
}

void DP(int i,int j)
{
    int k,x,y,S,cnt;
    FOR0(k,f[pre].size)
    {
        S=f[pre].st[k];
        cnt=f[pre].cnt[k];
        if(j==1)
        {
            if(getBit(S,m)) continue;
            S=S<<2;
        }
        x=getBit(S,j-1);
        y=getBit(S,j);
        S=set0(S,j-1);
        S=set0(S,j);
        if(s[i][j]==‘*‘)
        {
            if(x||y) continue;
            add(S,cnt);
            continue;
        }
        if(!x&&!y)
        {
            add(set1(S,j),cnt);
            add(set1(S,j-1),cnt);
            S=set3(S,j-1);
            S=set3(S,j);
            add(S,cnt);
        }
        else if(x&&y)
        {
            if(x==1&&y==1) add(S,cnt);
        }
        else if(x||y)
        {
            if(x==3) add(set3(S,j),cnt),add(S,cnt);
            else if(x==1) add(set1(S,j),cnt),add(set3(S,j-1),cnt);

            if(y==3) add(set3(S,j-1),cnt),add(S,cnt);
            else if(y==1) add(set1(S,j-1),cnt),add(set3(S,j),cnt);
        }
    }
}

int main()
{
    init();
    pre=0; cur=1;
    f[pre].init(); f[pre].add(0,1);
    int i,j;
    FOR1(i,n) FOR1(j,m)
    {
        f[cur].init();
        DP(i,j);
        swap(pre,cur);
    }
    int ans=0;
    FOR0(i,f[pre].size) if(f[pre].st[i]==0) ans=f[pre].cnt[i];
    PR(ans);
}

BZOJ 2331 地板(插头DP),布布扣,bubuko.com

时间: 2024-10-14 12:42:12

BZOJ 2331 地板(插头DP)的相关文章

【BZOJ】2331: [SCOI2011]地板 插头DP

[题意]给定n*m的地板,有一些障碍格,要求用L型的方块不重不漏填满的方案数.L型方块是从一个方格向任意两个相邻方向延伸的方块,不能不延伸.n*m<=100. [算法]插头DP [题解]状态0表示无插头,1表示能拐弯的插头,2表示不能拐弯的插头.(有插头,方块就必须必须延伸到该格),考虑转移即可. 注意可以凭空产生一个能拐弯的插头. n*m<=100,当m>10的时候将i,j互换. #include<cstdio> #include<cstring> #inclu

2331: [SCOI2011]地板 插头DP

国际惯例的题面:十分显然的插头DP.由于R*C<=100,所以min(R,C)<=10,然后就可以愉悦地状压啦.我们用三进制状压,0表示没有插头,1表示有一个必须延伸至少一格且拐弯的插头,2表示有一个必须延伸一格且不可以拐弯的插头.转移的话就十分显然了.00->22,表示用这个格子作为开始的拐角.00->10,表示用这个格子向下延伸.00->01,表示用这个格子向右延伸.01->10,表示这个格子连接上下.01->02,表示在这个格子作为中间的拐角.02->

【插头DP】 BZOJ 2331 地板

通道:http://www.lydsy.com/JudgeOnline/problem.php?id=2331 题意:用L型的填满格子,有障碍. 思路:0表示该格无插头,1表示向内,2表示向外. (1)如果left插头和up插头都为0   1.从未决策右边和下边格子引两条箭头 2.从该格向未决策的右边引外插头 3.从该格向未决策的下边引外插头 (2)如果left插头或者up插头为0,如果有拐角,则按原方向转移. (3)如果left插头和up插头均为1,状态合法 代码: 1 #include <c

bzoj 2331: [SCOI2011]地板 插头dp

用四进制表示状态. 用hash表把一个四进制数映射到一个小数上. 这样就可以memset了. 转移的时候分类讨论一下,特判下边界情况. 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 #define bq 1<<bit[j] 6 #define bp 1<<bit[j-1] 7 using namespace std

【BZOJ2331】[SCOI2011]地板 插头DP

[BZOJ2331][SCOI2011]地板 Description lxhgww的小名叫“小L”,这是因为他总是很喜欢L型的东西.小L家的客厅是一个的矩形,现在他想用L型的地板来铺满整个客厅,客厅里有些位置有柱子,不能铺地板.现在小L想知道,用L型的地板铺满整个客厅有多少种不同的方案? 需要注意的是,如下图所示,L型地板的两端长度可以任意变化,但不能长度为0.铺设完成后,客厅里面所有没有柱子的地方都必须铺上地板,但同一个地方不能被铺多次. Input 输入的第一行包含两个整数,R和C,表示客厅

【BZOJ 2331】 [SCOI2011]地板

2331: [SCOI2011]地板 Time Limit: 5 Sec  Memory Limit: 128 MB Submit: 598  Solved: 264 [Submit][Status][Discuss] Description lxhgww的小名叫"小L",这是因为他总是很喜欢L型的东西.小L家的客厅是一个的矩形,现在他想用L型的地板来铺满整个客厅,客厅里有些位置有柱子,不能铺地板.现在小L想知道,用L型的地板铺满整个客厅有多少种不同的方案? 需要注意的是,如下图所示,

BZOJ 2595 游览计划(插头DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2595 题意:给出一个数字矩阵.求一个连通块包含所有的数字0且连通块内所有数字之和最小. 思路:对于每个格子,是0则必须要选.那么对于不选的格子(i,j)在什么时候可以不选呢?必须同时满足以下两个条件: (1)(i,j)不是0: (2)(i-1,j)不选或者(i-1,j)选了但是轮廓线上还有别的地方与(i-1,j)是一个连通块. int Pre[105][N],op[105][N]; s

bzoj 1187: [HNOI2007]神奇游乐园 插头dp

1187: [HNOI2007]神奇游乐园 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 668  Solved: 337[Submit][Status][Discuss] Description 经 历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这是一个游 乐场,专为旅途中疲惫的人设计.娱乐场可以看成是一块大小为n×m的区域,且这个n×m的区域被分成n×m个

【题解】互不侵犯 SCOI 2005 BZOJ 1087 插头dp

以前没学插头dp的时候觉得这题贼难,根本不会做,学了才发现原来是一裸题. 用二进制表示以前的格子的状态,0表示没放国王,1表示放了国王. 假设当前位置为(x,y),需要记录的是(x-1,y-1)至(x,y-1)的信息,共n+1个点. 每个状态有两种决策,第一种是这个格子不放国王,直接转移. 第二种是这个格子放国王,需要满足几个条件才能进行这步转移,条件很显然,具体见代码和注释. 因为状态数很少,所以也用不到BFS转移状态和Hash的技巧,所以这题还是很清真的,细节不多,码量也很小. #inclu