zoukankan      html  css  js  c++  java
  • [SCOI2005]互不侵犯

    题目描述

    在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。


    由于每摆上一个棋子,需要查看周围9个位置,导致搜索的复杂度直接爆炸((n^2)个格子里选k个格子满足条件,搜索复杂度不太好估计,但是(C(k,n^2))一定很大)

    因此需要预处理每一行的合法状态,然后进行递推(状压dp),每一位所记录的状态都是合法的

    对于每一行,先枚举这一行的预备状态,然后枚举这一行的预备容量(类似背包枚举容量),再枚举上一行的状态(这个状态满足递推关系所以满足题目条件),如果两行judge合法则从上一行的状态转移到这一行

    设上一行的状态下标为k,这一行的状态下标为j(其所包含1的数量为num[j])

    即写出状态转移方程:(dp[i][l][j] += dp[i - 1][l - num[j]][k])(类似背包,如果l-num[j]有状态会被加上来,没有就当无事发生);

    别忘了初始状态为dp[0][0][0]=1,即第0行没有摆棋子的0号状态为合法状态

    最后统计第n行有k个棋子的每个状态所满足条件的合法状态数即可

    记得开long long


    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    #define ll long long
    #define fastio {ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);};
    using namespace std;
    const int inf = 1e9 + 7;
    const int maxn = 1e4 + 10;
    
    vector<pair<ll,ll> >zt;
    
    ll dp[11][200][200];
    
    ll judge(ll x)
    {
        ll cnt = 0;
        int flag = 0;
        while (x)
        {
            if (x & 1)
            {
                if (!flag)
                    flag = 1;
                else
                    return 0;
                cnt++;
            }
            else
                flag = 0;
            x >>= 1;
        }
        return cnt;
    }
    
    int main()
    {
        fastio;
        ll n, K;
        cin >> n >> K;
        zt.push_back({0,0});
        for (int i = 1; i < 1 << n; i++)
        {
            ll tot;
            if (tot = judge(i))
            {
                //cout << i << " " << tot << endl;
                zt.push_back({ i,tot });
            }
        }
        dp[0][0][0] = 1;
        for (int i = 1; i <= n; i++)
            for (int j = 0; j < zt.size(); j++)
                for (int l = zt[j].second; l <= K; l++)
                    for (int k = 0; k < zt.size(); k++)
                    {
                        int tmp = zt[j].first, ttmp = zt[k].first;
                        if (tmp & ttmp || (tmp << 1) & ttmp || (tmp >> 1)& ttmp)continue;
                        dp[i][l][j] += dp[i - 1][l - zt[j].second][k];
                    }
        ll ans = 0;
        for (int i = 0; i < zt.size(); i++)
            ans += dp[n][K][i];
        cout << ans;
        return 0;
    }
    
  • 相关阅读:
    A4988和CNC SHIELD使用方法 步进电机
    MTP 写字机器
    s*s*r备用
    VHDL 例程
    ESP8266 使用
    世界四大航海家
    第六周学习进度总结
    关于tensorflow版本报错问题的解决办法
    第五周学习进度总结
    机器学习对文本的聚类KMeans
  • 原文地址:https://www.cnblogs.com/ruanbaiQAQ/p/13237175.html
Copyright © 2011-2022 走看看