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

    数据这么小,不是暴力就是状压。

    考虑状压dp,f[i][j]表示前i大的数填完后,状态集合为j的情况。

    这样我们可以从小到大填数。对于状态更新。

    首先如果当前i我们填在一个谷底那么就是状态直接相加。

    比较复杂的情况是我们填在非谷地,因为我们要知道还可以填哪些位置,而这些位置是随便填的,只要根据乘法原理乘一下就能更新

    首先如果一个非谷地旁边是谷底,那么不能填,如果已经被填过了,那么也不能填,我们需要预处理这些状态可以看我的代码理解。

    但是这样求出来并不是答案,因为我们现在满足的是谷地一定填好了,但是非谷地可能在更新中成为谷地,这个意思是说,我们更新的时候是根据乘法原理更新的

    这里就会存在某个被定义为非谷地的点周围填的数都比他大,这样它就成为谷地了,但是这样是非法的,因此我们考虑去重。

    一般这种去重很容易想到容斥原理,将某个可能成为谷地的非谷地人为设计为谷底,之后根据奇偶改变量决定是加还是减,这是容斥的基本套路

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<ll,ll> pll;
    const int N=5e5+10;
    const int inf=0x3f3f3f3f;
    const int mod=772002;
    int n,m;
    int f[30][1200];
    char g[30][30];
    char tmp[30][30];
    map<int,pll> m1;
    int pos[N],mou[N];
    ll ans;
    int dx[]={-1,-1,0,1,1,1,0,-1};
    int dy[]={0,1,1,1,0,-1,-1,-1};
    int sx[N],sy[N];
    bool check(){
        int i,j;
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                if(g[i][j]!='X')
                    continue;
                for(int k=0;k<8;k++){
                    int x=i+dx[k];
                    int y=j+dy[k];
                    if(x&&x<=n&&y&&y<=m){
                        if(g[x][y]=='X')
                            return true;
                    }
                }
            }
        }
        return false;
    }
    ll solve(){
        int i,j;
        memset(f,0,sizeof f);
        f[0][0]=1;
        int cnt=0;
        int num=n*m;
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                if(g[i][j]=='X'){
                    cnt++;
                    sx[cnt-1]=i;
                    sy[cnt-1]=j;
                }
            }
        }
        memset(tmp,'.',sizeof tmp);
        int mx=1<<cnt;
        for(i=0;i<mx;i++){
            mou[i]=0;
            for(j=0;j<cnt;j++){
                if(i>>j&1){
                    mou[i]++;
                }
                else{
                   tmp[sx[j]][sy[j]]='Y';
                }
            }
            pos[i]=num-cnt;
            for(int l=1;l<=n;l++){
                for(int r=1;r<=m;r++){
                    if(g[l][r]=='X')
                        continue;
                    for(int k=0;k<8;k++){
                        int a=l+dx[k];
                        int b=r+dy[k];
                        if(a<=n&&a&&b&&b<=m){
                            if(tmp[a][b]=='Y'){
                                pos[i]--;
                                break;
                            }
                        }
                    }
                }
            }
            for(int k=0;k<cnt;k++){
                tmp[sx[k]][sy[k]]='.';
            }
        }
        for(i=0;i<num;i++){
            for(j=0;j<mx;j++){
                if(!f[i][j])
                    continue;
                for(int k=0;k<cnt;k++){
                    if(!((j>>k)&1)){
                        f[i+1][j|(1<<k)]=(f[i+1][j|(1<<k)]+f[i][j])%mod;
                    }
                }
                f[i+1][j]=(f[i+1][j]+f[i][j]*(pos[j]-i+mou[j])%mod)%mod;
            }
        }
        return f[num][mx-1];
    }
    void dfs(int u,int num){
        if(u==n*m+1){
            if(num%2==0)
                ans=(ans+solve())%mod;
            else
                ans=(ans-solve()+mod)%mod;
            return ;
        }
        int x=m1[u].first;
        int y=m1[u].second;
        int i;
        for(i=0;i<8;i++){
            int a=x+dx[i];
            int b=y+dy[i];
            if(a&&a<=n&&b&&b<=m){
                if(g[a][b]=='X')
                    break;
            }
        }
        if(i==8&&g[x][y]=='.'){
            g[x][y]='X';
            dfs(u+1,num+1);
            g[x][y]='.';
        }
        dfs(u+1,num);
    }
    int main(){
        ios::sync_with_stdio(false);
        int times=1;
        while(cin>>n>>m){
            m1.clear();
            int i,j;
            int id=0;
            for(i=1;i<=n;i++){
                for(j=1;j<=m;j++){
                    cin>>g[i][j];
                    m1[++id]={i,j};
                }
            }
            if(check()){
                cout<<"Case #"<<times++<<": ";
                cout<<0<<endl;
            }
            else{
                ans=0;
                dfs(1,0);
                cout<<"Case #"<<times++<<": ";
                cout<<ans<<endl;
            }
        }
        return 0;
    }
    View Code
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    Linq 实例
    VS的无用文件
    我在vs文本编辑中常用的快捷键----常更新
    EF+MVC学习中的不理解的问题
    Lambda表达式
    Linq学习(主要参考linq之路)----2LINQ方法语法
    WPF编译时提示“...不包含适合于入口点的静态‘Main’方法 ...”
    SQL
    SQL Server
    sql 判断表是否存在
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/13597082.html
Copyright © 2011-2022 走看看