zoukankan      html  css  js  c++  java
  • luogu P1896 [SCOI2005] 互不侵犯 //状压DP

    原题链接

    这道题是状压第2题,刚开始的想法还是naive了点,想要拿整个棋盘作为状态。

    仔细分析就会发现,存整个棋盘的做法有大量的空间浪费,

    因为一颗棋子的状态只由4个格子决定,转移时存整个棋盘实在是太亏了。

    为了方便我们转移,用一行上的棋子情况来做状态,只用判断这一行是否合法和是否与上一行的状态冲突就行了。

    这一行是否合法可以先预处理出来,并同时处理这一行有多少个棋子。

    dp[现在第几行][这一行的状态][到目前为止有多少棋子]

    其实最难的地方在于棋子个数的限制,但我打到一半看的题解所以没有仔细想=  =

    DP之路,长而难行。

    代码:

    #include<bits/stdc++.h>
    
    using namespace std ;
    
    long long dp[20][2000][100];
    int n,m,can[2000],csz,MAX,num[2000];
    long long ans;
    
    int getsum(int x){
        int ret=0;
        while(x){
            ret+=(x&1);
            x>>=1;
        }
        return num[csz]=ret;
    }
    
    void DP(){
        int MAX = (1<<n)-1;
        for(int i=0;i<=MAX;i++){
            if(!(i&(i<<1))) can[++csz]=i,dp[1][csz][getsum(i)]=1;
        }
        for(int i=2;i<=n;i++){
            for(int j=1;j<=csz;j++){
                int x=can[j];
                for(int k=1;k<=csz;k++){
                    int y=can[k];
                    if((x&y) || (x&(y<<1)) || (x&(y>>1))) continue;
                    for(int l=0;l+num[j]<=m;l++){
                        dp[i][j][num[j]+l] += dp[i-1][k][l];
                    }
                }
            }
        }
        for(int i=1;i<=csz;i++){
            ans+=dp[n][i][m];
        }
        return;
    }
    
    int main(){
        cin>>n>>m;
        DP();
        cout<<ans<<endl;
        return 0;
    }

    TAG:SIN_XIII⑨

  • 相关阅读:
    【C-数据类型 常量 变量】
    【OC简介-类和对象】
    【ios面试总结】
    【OC基础语法考试】
    【C-01关键字】
    UI3
    ui2
    UI
    C++使用shell命令
    字典
  • 原文地址:https://www.cnblogs.com/SINXIII/p/10863881.html
Copyright © 2011-2022 走看看