zoukankan      html  css  js  c++  java
  • HDU5838 Mountain(状压DP + 容斥原理)

    题目

    Source

    http://acm.hdu.edu.cn/showproblem.php?pid=5838

    Description

    Zhu found a map which is a N∗M rectangular grid.Each cell has a height and there are no two cells which have the same height. But this map is too old to get the clear information,so Zhu only knows cells which are valleys.

    A cell is called valley only if its height is less than the heights of all its adjacent cells.If two cells share a side or a corner they are called adjacent.And one cell will have eight adjacent cells at most.

    Now give you N strings,and each string will contain M characters.Each character will be '.' or uppercase 'X'.The j-th character of the i-th string is 'X' if the j-th cell of the i-th row in the mountain map is a valley, and '.' otherwise.Zhu wants you to calculate the number of distinct mountain maps that match these strings.

    To make this problem easier,Zhu defines that the heights are integers between 1 and N∗M.Please output the result modulo 772002.

    Input

    The input consists of multiple test cases.

    Each test case begins with a line containing two non-negative integers N and M. Then N lines follow, each contains a string which contains M characters. (1≤N≤5,1≤M≤5).

    Output

    For each test case, output a single line "Case #x: y", where x is the case number, starting from 1. And y is the answer after module 772002.

    Sample Input

    2 4
    .X..
    ...X
    4 2
    X.
    ..
    ..
    X.
    1 2
    XX

    Sample Output

    Case #1: 2100
    Case #2: 2520
    Case #3: 0

    分析

    题目大概说给一张大小n*m由'X'或'.'标记的图,要在其各个位置填入1到n*m这几个数,满足'X'填入的数是极小的(小于周围八个数)且'.'填入的数不是极小的,求有几种填法。

    好难的感觉。。
    考虑把数从小到大依次填入:

    • dp[i][S]表示当前已经填入数字1...i,且已经被填数的'X'集合为S的方案数(因为合法的'X'最多有9个所以用9位二进制压缩表示S即可)

    通过将i+1填入转移到dp[i+1]的状态:

    • 可以选择把i+1填入下一个还没被填的'X'位置x
    • 也可以填入'.'的位置,这个点'.'的位置不能是未填的'X'周围,因为是从小到大填数的

    这样子得到的方案数得到的不是答案要的方案数,因为它还包含了'.'填入的数是极小的,这个用容斥原理搞一下,具体就是用一个dfs搜出所有合法的'.'变为'X'的情况,奇数个减,偶数个加。。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int n,m;
    
    int dx[]={0,0,1,-1,1,-1,1,-1};
    int dy[]={1,-1,0,0,1,-1,-1,1};
    char map[5][5];
    
    long long d[26][1<<9];
    int pos[1<<9],siz[1<<9];
    
    long long dp(){
        int cnt=0,x[9],y[9];
        for(int i=0; i<n; ++i){
            for(int j=0; j<m; ++j){
                if(map[i][j]=='X'){
                    x[cnt]=i; y[cnt]=j;
                    ++cnt;
                }
            }
        }
        memset(siz,0,sizeof(siz));
        for(int s=0; s<(1<<cnt); ++s){
            for(int i=0; i<cnt; ++i){
                if(s>>i&1){
                    map[x[i]][y[i]]='Y';
                    ++siz[s];
                }
            }
            int res=0;
            for(int i=0; i<n; ++i){
                for(int j=0; j<m; ++j){
                    if(map[i][j]!='.') continue;
                    bool flag=1;
                    for(int k=0; k<8; ++k){
                        int nx=i+dx[k],ny=j+dy[k];
                        if(nx<0 || nx>=n || ny<0 ||ny>=m) continue;
                        if(map[nx][ny]=='X'){
                            flag=0;
                            break;
                        }
                    }
                    if(flag) ++res;
                }
            }
            pos[s]=res;
            for(int i=0; i<cnt; ++i){
                if(s>>i&1){
                    map[x[i]][y[i]]='X';
                }
            }
        }
    
        memset(d,0,sizeof(d));
        d[0][0]=1;
        for(int i=0; i<n*m; ++i){
            for(int j=0; j<(1<<cnt); ++j){
                if(d[i][j]==0) continue;
                for(int k=0; k<cnt; ++k){
                    if(j>>k&1) continue;
                    d[i+1][j^(1<<k)]+=d[i][j];
                    d[i+1][j^(1<<k)]%=772002;
                }
                d[i+1][j]+=d[i][j]*(pos[j]-i+siz[j]);
                d[i+1][j]%=772002;
            }
        }
        return d[n*m][(1<<cnt)-1];
    }
    
    long long ans;
    void dfs(int z,int k){
        if(z==n*m){
            if(k&1) ans-=dp();
            else ans+=dp();
            ans%=772002;
            return;
        }
        int x=z/m,y=z%m;
        bool flag=(map[x][y]!='X');
        for(int i=0; i<8; ++i){
            int nx=x+dx[i],ny=y+dy[i];
            if(nx<0 || nx>=n || ny<0 || ny>=m) continue;
            if(map[nx][ny]=='X'){
                flag=0;
                break;
            }
        }
        if(flag){
            map[x][y]='X';
            dfs(z+1,k+1);
            map[x][y]='.';
        }
        dfs(z+1,k);
    }
    
    bool check(){
        for(int i=0; i<n; ++i){
            for(int j=0; j<m; ++j){
                if(map[i][j]=='.') continue;
                for(int k=0; k<8; ++k){
                    int nx=i+dx[k],ny=j+dy[k];
                    if(nx<0 || nx>=n || ny<0 || ny>=m) continue;
                    if(map[nx][ny]=='X') return 0;
                }
            }
        }
        return 1;
    }
    
    int main(){
        int cse=0;
        while(~scanf("%d%d",&n,&m)){
            for(int i=0; i<n; ++i){
                for(int j=0; j<m; ++j){
                    scanf(" %c",&map[i][j]);
                }
            }
            if(!check()){
                printf("Case #%d: 0
    ",++cse);
                continue;
            }
            ans=0;
            dfs(0,0);
            if(ans<0) ans+=772002;
            printf("Case #%d: %lld
    ",++cse,ans);
        }
        return 0;
    }
    
  • 相关阅读:
    Java基础——Java反射机制
    Java基础——Java常用类
    Java基础——多线程
    Java基础——IO流--转换流、标准输入输出流
    Java基础——IO流
    Java基础——枚举与注解
    Java基础——泛型
    codeforces B. Bear and Strings 解题报告
    codeforces A. Black-and-White Cube 解题报告
    codeforces B. Ping-Pong (Easy Version) 解题报告
  • 原文地址:https://www.cnblogs.com/WABoss/p/6016813.html
Copyright © 2011-2022 走看看