• P3160 [CQOI2012]局部极小值(dfs+状压dp)


    题目描述

    有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次。如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值。给出所有局部极小值的位置,你的任务是判断有多少个可能的矩阵。

    输入格式

    输入第一行包含两个整数n和m(1<=n<=4, 1<=m<=7),即行数和列数。以下n行每行m个字符,其中”X“表示局部极小值,”.“表示非局部极小值。

    输出格式

    输出仅一行,为可能的矩阵总数除以12345678的余数。

    输入输出样例

    输入 #1
    3 2
    X.
    ..
    .X
    输出 #1
    60
    SOLUTION:
    见洛谷
    CODE:
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    char a[10];
    int m,n,min[6][10];//描述整个矩阵
    int num,x[30],y[30];//描述坑的个数、位置
    int w=12345678;//膜
    int dx[10]={-1,-1,-1,0,0,1,1,1,0};//移动位置
    int dy[10]={-1,0,1,-1,1,-1,0,1,0};
    int vis[6][10],f[29][(1<<8)+10],hi[1<<9];//dp用到的东西
    int dp(){
        int i,j,k;
        memset(f,0,sizeof(f));
        f[0][0]=1;
        for(i=0;i<(1<<num);i++){//预处理出每个状态i对应的可填点数量
            hi[i]=n*m;
            memset(vis,0,sizeof(vis));
            for(j=0;j<num;j++)if(!(i&(1<<j)))for(k=0;k<9;k++)vis[x[j]+dx[k]][y[j]+dy[k]]=1;
            for(j=1;j<=n;j++)for(k=1;k<=m;k++)if(vis[j][k])hi[i]--;
        }
        for(i=1;i<=n*m;i++){//枚举填哪个数
            for(j=0;j<(1<<num);j++){//枚举状态
                if(hi[j]-i+1>0)f[i][j]+=f[i-1][j]*(hi[j]-i+1),f[i][j]%=w;
                for(k=0;k<num;k++)if((1<<k)&j)f[i][j]+=f[i-1][j^(1<<k)],f[i][j]%=w;
            }
        }
        return f[n*m][(1<<num)-1];
    }
    int cnt=0;
    int P=0;
    int dfs(int X,int Y){
        if(Y==m+1)X++,Y=1;
        if(X==n+1)
        {
            if(cnt%2==1)P-=dp();else P+=dp();
            P%=w;P+=w;P%=w;
            return 0;
        }
         dfs(X,Y+1);
     int i;
        for(i=0;i<9;i++)if(min[X+dx[i]][Y+dy[i]])return 1;
    
        //如果没return说明这个地方是个可能变成坑的地方,那就把它变成坑dfs一下
        x[num]=X;y[num++]=Y;
        min[X][Y]=1;
        cnt++;
        dfs(X,Y+1);
        min[X][Y]=0;num--;//别忘了变回去
        cnt--;
        return  1;
    }
    int main(){
        int i,j;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++){
            scanf("%s",a+1);
            for(j=1;j<=m;j++)if(a[j]=='X'){
                min[i][j]=1;
                x[num]=i;y[num++]=j;
            }
        }
        for(i=0;i<num;i++)for(j=0;j<i;j++)if(abs(x[i]-x[j])<2&&abs(y[i]-y[j])<2)return printf("0"),0;
        if(!num)return printf("0"),0;
        dfs(1,1);
        printf("%d",P);
        return 0;
    }
    
    
    

      








  • 相关阅读:
    机器学习
    arm 基本
    阿里RDS备份恢复
    hive 调用java的函数和科学记数法转换
    hive 调用java的函数和科学记数法转换
    hive处理hbase数据
    hive处理hbase数据
    Sqoop导入mysql数据到Hbase
    Sqoop导入mysql数据到Hbase
    Hbase基础操作
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/11375415.html
Copyright © 2020-2023  润新知