zoukankan      html  css  js  c++  java
  • dp合集 广场铺砖问题&&硬木地板

    dp合集 广场铺砖问题&&硬木地板


    很经典了吧。。。

    前排:思想来自yali朱全民dalao的ppt百度文库免费下载

    后排:STO朱全民OTZ


    广场铺砖问题

    有一个 W 行 H 列的广场,需要用 1*2 小砖铺盖,小砖之间互相不能重叠,问
    有多少种不同的铺法?
    输入数据:
    只有一行 2 个整数,分别为 W 和 H,( 1<=W, H<=11)
    输出数据:
    只有 1 个整数,为所有的铺法数。
    样例:
    Floor.in
    2 4
    Floor.out
    5

    dfs、bfs。。。算了吧
    然而我看了一眼ppt,这不是SBT吗???
    然后就写出来了
    设f[i][j]表示第i行,状态为j的转移方法数
    具体思想:一个状态有两种方式转移:全竖放转移and横放一个转移。
    然后WA了
    原因:横放可能有重复(比如□□□□,可以先左边两个也可以先右边两个),然后GG

    // It is made by XZZ
    #include<cstdio>
    #include<algorithm>
    #define lb(a) (a&-a)
    #define Fname "floor"
    using namespace std;
    #define rep(a,b,c) for(rg int a=b;a<=c;a++)
    #define drep(a,b,c) for(rg int a=b;a>=c;a--)
    #define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
    #define il inline
    #define rg register
    #define vd void
    typedef long long ll;
    il int gi(){
        rg int x=0;rg char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x;
    }
    int f[12][1<<11];
    int cnt[1<<11],s[1<<11];
    il bool cmp(int a,int b){return cnt[a]<cnt[b];}
    int main(){
    #ifdef xzz
        freopen(Fname".in","r",stdin);
        freopen(Fname".out","w",stdout);
    #endif
        int n=gi(),m=gi();
        if((n*m)&1){puts("0");return 0;}
        f[0][0]=1;
        int tot=(1<<m)-1;
        rep(i,0,tot){
    	int j=i;
    	while(j)++cnt[i],j-=lb(j);
        }
        rep(i,0,tot)s[i]=i;
        sort(s+1,s+tot+1,cmp);
        int g,j;
        rep(i,0,n-1)rep(jj,0,tot){
    	j=s[jj];
    	g=f[i][j];
    	printf("f[%d][%d]=%d
    ",i,j,f[i][j]);
    	f[i+1][(~j)&tot]+=g;//所有的都竖放
    	rep(k,0,m-2)if(!((1<<k)&j)&&!((1<<k+1)&j))f[i][j|(1<<k)|(1<<k+1)]+=g;
        }
        printf("%d
    ",f[n][0]);
        return 0;
    }
    

    解决办法:一次转移
    即通过dfs完成转移,做到不重不漏
    在一个状态下dfs下一排可能的所有状态
    具体见ppt

    // It is made by XZZ
    #include<cstdio>
    #include<algorithm>
    #define lb(a) (a&-a)
    #define Fname "floor"
    using namespace std;
    #define rep(a,b,c) for(rg int a=b;a<=c;a++)
    #define drep(a,b,c) for(rg int a=b;a>=c;a--)
    #define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
    #define il inline
    #define rg register
    #define vd void
    typedef long long ll;
    il int gi(){
        rg int x=0;rg char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x;
    }
    ll f[12][1<<11],n,m;
    il vd dfs(const ll&F,const int&i,const int&j,int x,int now){
        if(now==m)f[i+1][x]+=F;
        else if(j&(1<<now))dfs(F,i,j,x,now+1);//已经有了
        else{
    	dfs(F,i,j,x|(1<<now),now+1);//竖着
    	if((now!=m-1)&&!(j&(1<<now+1)))dfs(F,i,j,x,now+2);//横着
        }
    }
    int main(){
    #ifdef xzz
        freopen(Fname".in","r",stdin);
        freopen(Fname".out","w",stdout);
    #endif
        n=gi(),m=gi();
        if((n*m)&1){puts("0");return 0;}
        f[0][0]=1;
        rep(i,0,n-1)rep(j,0,(1<<m)-1)dfs(f[i][j],i,j,0,0);
        printf("%lld
    ",f[n][0]);
        return 0;
    }
    

    其实还可以有更快的:每个j转移过去的都相同,可以先预处理每个j转移的,用邻接表实现,应该快的飞起
    虽然我懒得写了(逃


    硬木地板

    举行计算机科学家盛宴的大厅的地板为 M×N (1<=M<=9, 1<=N<=9)的矩形。现在必须要铺上硬木地板砖。可以使用的地板砖形状有两种:

    1. 2×1 的矩形砖
    2. 2×2 中去掉一个 1×1 的角形砖
      你需要计算用这些砖铺满地板共有多少种不同的方案。
      注意:必须盖满,地板砖数量足够多,不能存在同时被多个板砖覆盖的部分。
      输入数据
      包含 M 和 N。
      输出数据
      输出方案总数,如果不可能那么输出 0 。
      样例
      输入:floor.in
      2 3
      输出:floor.out
      5

    会上面那个基本就会这个了额。。。
    改一下dfs就好了

    // It is made by XZZ
    #include<cstdio>
    #include<algorithm>
    #define Fname "floor2"
    using namespace std;
    #define rep(a,b,c) for(rg int a=b;a<=c;a++)
    #define drep(a,b,c) for(rg int a=b;a>=c;a--)
    #define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
    #define il inline
    #define rg register
    #define vd void
    typedef long long ll;
    il int gi(){
        rg int x=0;rg char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x;
    }
    ll f[10][1<<9],n,m;
    il vd dfs(const ll&F,const int&i,const int&j,int x,int now){
        if(now==m)f[i+1][x]+=F;
        else if(j&(1<<now))dfs(F,i,j,x,now+1);
        else{
    	if(!(x&(1<<now))){
    	    dfs(F,i,j,x|(1<<now),now+1);//竖着
    	    if(now&&(!(x&(1<<now-1))))dfs(F,i,j,x|(1<<now)|(1<<now-1),now+1);//┘
    	    if(now!=m-1)dfs(F,i,j,x|(1<<now)|(1<<now+1),now+1);//└
    	}
    	if((now!=m-1)&&!(j&(1<<now+1))){
    	    dfs(F,i,j,x,now+2);//横着
    	    if(!(x&(1<<now)))dfs(F,i,j,x|(1<<now),now+2);//┌
    	    dfs(F,i,j,x|(1<<now+1),now+2);//┐
    	}
    	
        }
    }
    int main(){
    #ifdef xzz
        freopen(Fname".in","r",stdin);
        freopen(Fname".out","w",stdout);
    #endif
        n=gi(),m=gi();
        f[0][0]=1;
        rep(i,0,n-1)rep(j,0,(1<<m)-1)dfs(f[i][j],i,j,0,0);
        printf("%lld
    ",f[n][0]);
        return 0;
    }
    

    PS.具体参见上面ppt链接
  • 相关阅读:
    【应用安全】mssql db_owner权限拿shell
    【应用安全——XSS】input-hidden
    留言板
    Git配置多个SSH-Key
    13.InternalThreadLocalMap
    10.ChannelOutboundBuffer
    9.ChannelHandlerContext
    8.Future&Promise
    7.给大动脉来一刀-NioEventLoop 源码分析
    6.给大动脉来一刀
  • 原文地址:https://www.cnblogs.com/xzz_233/p/7550096.html
Copyright © 2011-2022 走看看