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

时间:2019-08-19
本文章向大家介绍P3160 [CQOI2012]局部极小值(dfs+状压dp),主要包括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;
}

  








原文地址:https://www.cnblogs.com/zhangbuang/p/11375415.html