动态规划-状态压缩DP

[SCOI2005] 互不侵犯

题目描述

https://www.luogu.com.cn/problem/P1896

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

注:数据有加强(2018/4/25)

输入格式

只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

输出格式

所得的方案数

样例 #1

样例输入 #1

3 2

样例输出 #1

16

思路

学习状态压缩DP,首先需要熟悉各种位运算:

  • &:两位都为1才得1
  • |:有1得1
  • ^:相同为0,不同为1
  • ~:0变1,1变0
  • <<:左移一次相当于✖️2,例如1<<n相当于 2 n 2^n 2n, 5<<3相当于 5 ∗ 2 3 5*2^3 523
  • >>:右移:相当于➗2

为了求解本题,我们使用二进制数记录每行都状态:例如101代表第一格和第三格放国王,接着我们先筛选出行内合法的方案:

  1. 行内合法: 如果!(i&i>>1)为真,则i合法:

    i=5  1 0 1  i=6  1 1 0
    		 0 1 0  		 0 1 1
    
  2. 行间兼容:如果!(a&b)&&!(a&b>>1) &&!(a&b<<1)为真,则a,b兼容

    a&b表示列方向上不可以同时为1

    a&b>>1表示左对角不可以放1

    a&b<<1表示右对角不可以放1

  3. 状态表示:f[i,j,a]表示前i行已经放了j个国王,第i行的第a个状态的方案数

image.png

img

状态表示:f[i,j,a]表示前i行已经放了j个国王,第i行的第a个状态的方案数

  • 统计每个合法状态包含的国王数:看有几个1
  • img
  • 优先级:<<优先级高于&

代码

#include <bits/stdc++.h>

#define int long long
using namespace std;

int n, k;//棋盘行数,国王总数
int cnt = 0;//同一行的合法状态个数
int s[1 << 12];//同一行的合法状态集
int num[1 << 12];//每个合法状态包含的国王数
int f[12][144][1 << 12];//f[i,j,a]表示前i行放了j个国王,第i行第a个状态时的方案数

signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    cin >> n >> k;

    //预处理
    for (int i = 0; i < (1 << n); i++)//枚举一行的所有状态
        if (!(i & i >> 1))//如果不存在相邻的1
        {
            s[cnt++] = i;//保存一行的合法状态
            for (int j = 0; j < n; j++)
                num[i] += (i >> j & 1);//统计每个合法状态包含的国王数(看里面有几个1)
        }

    f[0][0][0] = 1;//不放国王也是一种方案

    for (int i = 1; i <= n + 1; i++)//枚举行
        for (int j = 0; j <= k; j++)//枚举国王数
            for (int a = 0; a < cnt; a++)//枚举第i行的合法状态
                for (int b = 0; b < cnt; b++)//枚举第i-1行的合法状态
                {
                    int c = num[s[a]];//第i行第a个状态的国王数
                    //可以继续放国王,不存在同列的1,不存在斜对角的1
                    if ((j >= c) && !(s[b] & s[a]) && !(s[b] & s[a] << 1) && !(s[b] & (s[a] >> 1)))
                        f[i][j][a] += f[i - 1][j - c][b];//从第i-1行向第i行转移
                }
    cout << f[n + 1][k][0];
    return 0;
}

[USACO06NOV]Corn Fields G 玉米田

题目描述

https://www.luogu.com.cn/problem/P1879

Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and can’t be planted. Canny FJ knows that the cows dislike eating close to each other, so when choosing which squares to plant, he avoids choosing squares that are adjacent; no two chosen squares share an edge. He has not yet made the final choice as to which squares to plant.

Being a very open-minded man, Farmer John wants to consider all possible options for how to choose the squares for planting. He is so open-minded that he considers choosing no squares as a valid option! Please help Farmer John determine the number of ways he can choose the squares to plant.

农场主 J o h n \rm John John 新买了一块长方形的新牧场,这块牧场被划分成 M M M N N N ( 1 ≤ M ≤ 12 ; 1 ≤ N ≤ 12 ) (1 \le M \le 12; 1 \le N \le 12) (1M12;1N12),每一格都是一块正方形的土地。 J o h n \rm John John 打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。

遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是 J o h n \rm John John 不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。

J o h n \rm John John 想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)

输入格式

第一行:两个整数 M M M N N N,用空格隔开。

2 2 2 到第 M + 1 M+1 M+1 行:每行包含 N N N 个用空格隔开的整数,描述了每块土地的状态。第 i + 1 i+1 i+1 行描述了第 i i i 行的土地,所有整数均为 0 0 0 1 1 1 ,是 1 1 1 的话,表示这块土地足够肥沃, 0 0 0 则表示这块土地不适合种草。

输出格式

一个整数,即牧场分配总方案数除以 100 , 000 , 000 100,000,000 100,000,000 的余数。

样例 #1

样例输入 #1

2 3
1 1 1
0 1 0

样例输出 #1

9

思路

  1. 行内合法: 如果!(i&i>>1)为真,则i合法:

    i=5  1 0 1  i=6  1 1 0
    		 0 1 0  		 0 1 1
    
  2. 行间兼容:如果!(a&b)&&(a&g[i]==a)为真,则a,b兼容

    如果g[i]的某一位为0的话,a的那一位只可以为0,

    如果g[i]的某一位为1的化,a的那一位可以为1或0

    即 a&g[i]==a

状态表示:f[i,a]表示所有已经摆完前i行,并且第i行的状态是a的所有摆放方案的集合的数量

状态计算: f [ i , a ] = ∑ f [ i − 1 , b ] f[i,a]=\sum f[i-1,b] f[i,a]=f[i1,b]

代码

#include <bits/stdc++.h>

#define int long long
using namespace std;

const int mod = 1e9;
int n, m;//玉米田的行数、列数
int g[14];//各行的状态值
int cnt;//同一行的合法状态个数
int s[1 << 14];//一行的合法状态集
int f[14][1 << 14];//f[i,a]表示已经种植前i行,第i行第a各状态时的方案数

signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    cin >> n >> m;
    //预处理
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            int x;
            cin >> x;
            g[i] = (g[i] << 1) + x;//保存各行的状态值
        }
    }

    for (int i = 0; i < 1 << m; i++)//枚举一行所有状态
        if (!(i & i >> 1))//如果不存在相邻的1
            s[cnt++] = i;

    f[0][0] = 1;//什么都不种植也是一种方案;
    for (int i = 1; i <= n + 1; i++)//枚举行
        for (int a = 0; a < cnt; a++)//枚举第i行的合法状态
            for (int b = 0; b < cnt; b++) //枚举第i-1行合法状态
            {
                //a种植在肥沃的土地上;a,b同列不同时为1
                if ((s[a] & g[i]) == s[a] && !(s[a] & s[b]))
                    f[i][a] = (f[i][a] + f[i - 1][b]) % mod;
            }
    cout << f[n + 1][0];

    return 0;
}

[NOI2001] 炮兵阵地

题目描述

https://www.luogu.com.cn/problem/P2704

司令部的将军们打算在 N × M N\times M N×M 的网格地图上部署他们的炮兵部队。

一个 N × M N\times M N×M 的地图由 N N N M M M 列组成,地图的每一格可能是山地(用 H \texttt{H} H 表示),也可能是平原(用 P \texttt{P} P 表示),如下图。

在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。

图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。

现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

输入格式

第一行包含两个由空格分割开的正整数,分别表示 N N N M M M

接下来的 N N N 行,每一行含有连续的 M M M 个字符,按顺序表示地图中每一行的数据。

输出格式

一行一个整数,表示最多能摆放的炮兵部队的数量。

样例 #1

样例输入 #1

5 4
PHPP
PPHH
PPPP
PHPP
PHHP

样例输出 #1

6

提示

对于 100 % 100\% 100% 的数据, N ≤ 100 N\le 100 N100 M ≤ 10 M\le 10 M10,保证字符仅包含 PH

思路

  1. 行内合法:!(i&i>>1) && !(i&i>>2)为真,则i合法
  2. 行间合法:!(a&b) &&!(a&c) &&!(b&c) &&(a&g[i]==a)为真,则a,b,c合法

状态表示:f[i,a,b]表示已经摆放了前i行,当前行是第i行的第a个状态,第i-1行的第b个状态能拜访的最大数量

状态计算:f[i,a,b]=max(f[i,a,b],f[i-1,b,c]+num[a])

空间压缩优化:只需要把i改为i&1

代码

#include <bits/stdc++.h>

#define int long long
using namespace std;

const int N = 110, M = 1 << 10;
int n, m;//行数,列数
int g[N];//保存地图各行数值
int cnt;//同一行的合法状态个数
int s[M];//同一行的合法状态集
int num[M];//每个合法状态包含1的个数
int f[N][M][M];//f[i,a,b]表示已经放好前i行,第i行第a各状态,第i-1行第b各状态时,能放置的最大数量



signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < m; j++) {
            char c;
            cin >> c;
            if (c == 'P') g[i] = (g[i] << 1) + 1;
            else g[i] = g[i] << 1;
        }
    }
    for (int i = 0; i < 1 << m; i++) {
        if (!(i & i >> 1) && !(i & i >> 2)) {
            s[cnt++] = i;
            for (int j = 0; j < m; j++) num[i] += (i >> j & 1);
        }
    }
    for (int i = 1; i <= n + 2; i++) {
        for (int a = 0; a < cnt; a++) {
            for (int b = 0; b < cnt; b++) {
                for (int c = 0; c < cnt; c++) {
                    if (!(s[a] & s[b]) && !(s[a] & s[c]) && !(s[b] & s[c]) &&
                        (g[i] & s[a]) == s[a] && (g[i - 1] & s[b]) == s[b])
                        f[i][a][b] = max(f[i][a][b], f[i - 1][b][c] + num[s[a]]);
                }
            }
        }
    }
    cout << f[n + 2][0][0];


    return 0;
}

蒙德里安的梦想

题目

链接:https://www.acwing.com/problem/content/293/

求把 N×M 的棋盘分割成若干个 1×2的长方形,有多少种方案。

例如当 N=2,M=4 时,共有 5 种方案。当 N=2,M=3 时,共有 3种方案。

如下图所示:

2411_1.jpg

输入格式

输入包含多组测试用例。

每组测试用例占一行,包含两个整数 N和 M。

当输入用例 N=0,M=0时,表示输入终止,且该用例无需处理。

输出格式

每个测试用例输出一个结果,每个结果占一行。

数据范围

1≤N,M≤11

输入样例:

1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0

输出样例:

1
0
1
2
3
5
144
51205

思路

image.png

代码

#include <bits/stdc++.h>

#define int long long
using namespace std;

const int N = 12, M = 1 << 12;
int st[M];
int f[N][M];


signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    int n, m;
    while (cin >> n >> m && (n || m)) {

        for (int i = 0; i < 1 << n; i++) {
            int cnt = 0;
            st[i] = true;
            for (int j = 0; j < n; j++)
                if (i >> j & 1) {
                    if (cnt & 1) {
                        st[i] = false; // cnt 为当前已经存在多少个连续的0
                        break;
                    }
                } else cnt++;
            if (cnt & 1) st[i] = false; // 扫完后要判断一下最后一段有多少个连续的0
        }

        memset(f, 0, sizeof f);
        f[0][0] = 1;
        for (int i = 1; i <= m; i++)//枚举列
            for (int j = 0; j < 1 << n; j++)//枚举第i列第状态
                for (int k = 0; k < 1 << n; k++)//枚举第i-1列的状态
                    //两列状态兼容:	不出现重叠1,不出现
                    if ((j & k) == 0 && (st[j | k]))
                        // j & k == 0 表示 i 列和 i - 1列同一行不同时捅出来
                        // st[j | k] == 1 表示 在 i 列状态 j, i - 1 列状态 k 的情况下是合法的.
                        f[i][j] += f[i - 1][k];
        cout << f[m][0] << endl;
    }


    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/22460.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

堪比ChatGPT,Claude注册和使用教程

新建了一个网站 https://ai.weoknow.com/ 每天给大家更新可用的国内可用chatGPT资源 Claude简介 Claude是一款人工智能聊天机器人。主要有以下特征: 使用自己的模型与训练方法,而不是基于GPT-3等开源框架。模型采用Transformer编码器与解码器的结构,并使用对话上下文的双向…

实验六 自动驾驶建模与仿真

【实验目的】 了解Matlab/Simulink软件环境&#xff0c;熟悉Simulink建模步骤&#xff1b;了解车辆运动控制的基本原理&#xff0c;学会简单的车辆运动控制建模及仿真&#xff1b;了解自动驾驶建模的基本过程&#xff0c;了解典型ADAS系统模型的应用特点。了解自动驾驶相关函数…

老司机解读香农定理、奈奎斯特定理、编码与调制

工程师都会考虑一个问题&#xff1a;信道上到底可以传输多大的数据&#xff0c;或者指定的信道上的极限传输率是多少。这就是信道容量的问题。例如&#xff0c;在xDSL系统中&#xff0c;我们使用的传输介质是仅有几兆带宽的电话线&#xff0c;而上面要传送几兆、十几兆甚至几十…

用 Python 写 3D 游戏

vizard介绍 Vizard是一款虚拟现实开发平台软件&#xff0c;从开发至今已走过十个年头。它基于C/C&#xff0c;运用新近OpenGL拓展模块开发出的高性能图形引擎。当运用Python语言执行开发时&#xff0c;Vizard同时自动将编写的程式转换为字节码抽象层(LAXMI)&#xff0c;进而运行…

WorkPlus AI助理 | 将企业业务场景与ChatGPT结合

近年来&#xff0c;人工智能成为了企业数字化转型的热门话题&#xff0c;作为被训练的语言模型&#xff0c;ChatGPT具备模拟对话、回答问题、写代码、写小说、进行线上内容创作的能力&#xff0c;还能根据聊天的上下文进行互动。作为一款新兴的人工智能应用程序&#xff0c;对于…

【IDEA】DeBug(图文并茂)

文章目录 01_Debug简介和意义02_IDEA中的Debug步骤03_跳转到当前代码执行的行04_步过调试的使用05_步入调试的使用06_强制步入调试的使用07_步出调试的使用08_回退断点调试的使用09_运行到光标处10_计算表达式11_条件断点12_多线程调试 IDAEA&#xff08;Interactive Data Anal…

【Linux高级 I/O(3)】如何使用阻塞 I/O 与非阻塞 I/O?——poll()函数

poll()函数介绍 系统调用 poll()与 select()函数很相似&#xff0c;但函数接口有所不同。在 select()函数中&#xff0c;我们提供三个 fd_set 集合&#xff0c;在每个集合中添加我们关心的文件描述符&#xff1b;而在 poll()函数中&#xff0c;则需要构造一个 struct pollfd 类…

分享18个好用的ChatGPT插件

上周ChatGPT又进化了&#xff0c;支持联网还有70几种第三方插件&#xff0c;不过还是老样子&#xff0c;只服务氪金玩家&#xff0c;免费端可能还得等等。之前只开放了俩插件&#xff0c;网络浏览器和代码解释器&#xff0c;只能说是真的不够用。 ChatGPT&#xff1a;不够&…

(一)before initialization of D3D(初始化D3D之前你需要了解的D3D基础知识)

什么是D3D? D3D全称Direct X 3D,即一组API可以用来针对GPU编程,不过他最主要的作用是用来渲染(不过现在也有很多其他应用比如d3d11va[Direct X 3D 11 Video API]用来进行硬件加速解码) Tips:Direct X 3D主要用来渲染,既然我们说到可以针对GPU编程了,当然不只是渲染的工作可以…

布隆过滤器和布谷鸟过滤器

过滤器使用场景&#xff1a; 比如有如下几个需求&#xff1a; 1.原本有10亿个号码&#xff0c;现在又来了10万个号码&#xff0c;要快速准确判断这10万个号码是否在10亿个号码库中&#xff1f;   解决办法一&#xff1a;将10亿个号码存入数据库中&#xff0c;进行数据库查询&…

iptables防火墙

iptables防火墙 一、iptables概述1.netfilter 与 iptables 的关系1&#xff09;netfilter2&#xff09;iptables 2.四表五链1&#xff09;四表2&#xff09;五链3&#xff09;表的匹配优先级4&#xff09;规则链之间的匹配顺序5&#xff09;规则链内的匹配顺序 二、iptables防火…

CodeForces.1806A .平面移动.[简单][判断可达范围][找步数规律]

题目描述&#xff1a; 题目解读&#xff1a; 给定移动规则以及起始点&#xff0c;终点&#xff1b;分析终点是否可达&#xff0c;可达则输出最小步数。 解题思路&#xff1a; 首先要判定是否可达。画图可知&#xff0c;对于题目给定的移动规则&#xff0c;只能到达起始点(a,b…

AWD竞赛全流程解析

AWD(Attack With Defense&#xff0c;攻防兼备)是一个非常有意思的模式&#xff0c;你需要在一场比赛里要扮演攻击方和防守方&#xff0c;攻者得分&#xff0c;失守者会被扣分。也就是说&#xff0c;攻击别人的靶机可以获取 Flag 分数时&#xff0c;别人会被扣分&#xff0c;同…

【数据分享】我国地级市绿地利用现状数据(9个指标\Shp格式)

绿地是城市生态的重要组成部分&#xff0c;在很多分析中都会用到绿地数据&#xff01;之前我们分享过Shp和Excel格式的全国地级市2003-2020年绿地面积数据&#xff08;可查看之前文章获悉详情&#xff09;&#xff0c;以及中国31个主要城市的绿地空间分布的栅格数据&#xff08…

ARM的读写内存指令与栈的应用

1.基础读写指令 写内存指令&#xff1a;STR MOV R1, #0xFF000000 MOV R2, #0x40000000 STR R1, [R2] 将R1寄存器中的数据写入到R2指向的内存空间 需注意&#xff0c;此命令是将R1中的数据写给R2所指向的内存空间&#xff0c;而不是直接把R1的数据赋给R2&#xff0c;R2寄存器…

华为、思科、Juniper 三厂商NAT配置详解

大家好&#xff0c;这里是网络技术联盟站。 本文给大家介绍华为、思科、Juniper 三大厂商NAT配置详解。 1. 华为&#xff08;Huawei&#xff09; 华为是一家全球领先的信息与通信技术解决方案供应商&#xff0c;其网络设备提供了强大的NAT功能。 下面是华为设备上的NAT配置示…

【软考中级】软件设计师选择题题集(一)

海明校验码是在n个数据位之外增设k个校验位,从而形成一个k+n位的新的码字, 使新的码字的码距比较均匀地拉大。n与k的关系是(1)。 (1)A.2k - 1≥n + k  B.2n - 1≤ n + k   C.n = k  D.n-1≤k 【答案】A 【解析】 【答案】B A 【解析】 在采用结构化方法进行系统分析时,…

这才是CSDN最系统的网络安全学习路线(建议收藏)

01 什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防两面…

ChatGPT 的议论文究竟写的怎么样?111 位高中教师告诉你答案

夕小瑶科技说 原创 作者 | 小戏、Python 在 OpenAI GPT-4 发布时发布的《GPT-4 Technical Report》中&#xff0c;其中很吸引人眼球的一部分是 GPT-4 应用于教育领域的出色表现&#xff0c;通过让 GPT-4 去完成美国的 AP 课程及考试&#xff0c;来评估 GPT-4 在多个学科中的性…

AtCoder Beginner Contest 302(A-D)

TOYOTA MOTOR CORPORATION Programming Contest 2023#2 (AtCoder Beginner Contest 302) Contest Duration: 2023-05-20(Sat) 20:00 - 2023-05-20(Sat) 21:40 (local time) (100 minutes) 暴搜场&#xff0c;1个小时出了4道&#xff0c;以为很有机会&#xff0c;结果E交了十发没…