【算法学习笔记】74. 枚举 状态压缩 填充方案 SJTU OJ 1391 畅畅的牙签袋(改)...
一开始想贪心,类似启发式搜索的感觉...后来觉得不行,而且很难写。
不如就枚举。可以通过0到2^W的中的每一个数的二进制形式来对应,第一行每个位置是否作为中心点放入十字格子的情况。
当此处为0时表示不放,1时表示放。
为什么只枚举第一行的所有情况就可以了呢。
因为第一行的情况确定之后,我们可以通过推理先改变第二行某些状态,然后再根据必须把第一行充满,可以确定第二排所有必须放十字块的位置。
生成该状态数之后,调用put函数,然后先影响下一行再通过结果来确定下一行。(这个算法的根基就是,处理每一行的时候要把上一行全部填满)
所以当到了最后一行被处理过之后,判断最后一行的合法性就可以了。
因为要处理很多位置...不想搞二进制很多事情了,就用bool数组来存状态了。
#include <iostream> #include <algorithm> using namespace std; const int INF = 9999999; bool map[20][20]={0}; bool cur[20][20]={0}; int H,W;void print(){cout<<"--------"<<endl;for (int i = 0; i < H; ++i){for (int j=0; j < W; ++j){cout<<cur[i][j];}cout<<endl;}cout<<"--------"<<endl; }void copyMap(){for (int i = 0; i < H; ++i)for (int j=0; j < W; ++j)cur[i][j] = map[i][j]; }void init(){cin>>H>>W;for (int i = 0; i < H; ++i){for (int j = 0; j < W; ++j){int l;cin>>l;map[i][j] = l%2; //偶数为0 奇数为1 }} }//计算k的二进制中有多少个1 int getOnes(int k){int ans = 0;while(k>0){if((k&1)) //如果最右侧是1ans++;k = k>>1;//每次扔出最右的一位; }return ans; }void put(int lineId, int state){//枚举时我们认为一个 状态数state 每个位置的 0表示不放 1表示放 那么进行填补for (int i = 0; i < W ; ++i) //从第一排第0个位置 到第W-1个 {if(state&(1<<i)){//表示是放的 则对两边及下方的进行填写if(lineId>=1)//可以不用写cur[lineId-1][i] = !cur[lineId-1][i];cur[lineId][i] = !cur[lineId][i];if(i>=1)cur[lineId][i-1] = !cur[lineId][i-1];cur[lineId][i+1] = !cur[lineId][i+1];cur[lineId+1][i] = !cur[lineId+1][i];}} }int build(){bool have = false;int res = INF;//首先要对第一排的放十字的所有可能情况进行枚举//然后根据第一行的摆放情况 可以确定第二行的摆放,依次决定第三行.....for (int i = 0; i < (1<<W); ++i)//一共有2^W种放的情况 {//每次枚举前先进行copy 不能直接在map上进行修改 copyMap();int cnt = getOnes(i);//对放的十字的个数进行记录put(0,i);//print();//第一排做完了 我们来根据第一排的情况 确定接下来每一排必须放十字的位置for (int k = 1; k < H; ++k){int curState = 0;//生成状态数 用来进行调用put函数for (int j = 0; j < W; ++j){if(cur[k-1][j])//如果上一行的这个地方是1 即是奇数 则肯定要在以这一行的这个位置为中心进行填补curState += (1<<j);}cnt += getOnes(curState);put(k,curState);}//放完之后要检查最后一行是不是已经被填满 如果是的话 则说明全体都被填成偶数bool ok = true;for (int j = 0; j < W; ++j){if(cur[H-1][j]){ok = false;break;}}if(ok){have = true;res = min(res,cnt);}}if(!have)res = -1;return res; }int main(int argc, char const *argv[]) {init();cout<<build()<<endl;return 0; }
转载于:https://www.cnblogs.com/yuchenlin/p/sjtu_oj_1391.html
【算法学习笔记】74. 枚举 状态压缩 填充方案 SJTU OJ 1391 畅畅的牙签袋(改)...相关推荐
- 【算法学习笔记】67.状态压缩 DP SJTU OJ 1383 畅畅的牙签袋
思想来自:http://blog.pureisle.net/archives/475.html 主要思想是用1和0来表示是否被填,然后根据两行之间的状态关系来构建DP方程. 1.首先初始化第一行 计算 ...
- 【算法学习笔记】35.高精度 竖式乘法 SJTU OJ 1274
Description 输入a,b 输出a*b的竖式乘法,格式见样例. Sample Input1 11 9 Sample Output1 119 -- 99 Sample Input2 10 10 ...
- 两个字符串的最长公共子序列长度_算法学习笔记(58): 最长公共子序列
(为什么都更了这么多篇笔记了,这时候才讲这么基础的内容呢?因为我本来以为LCS这种简单的DP不用讲的,结果CF不久前考了LCS的变式,然后我发现由于自己对LCS一点都不熟,居然写不出来 ,于是决定还是 ...
- 【基础】基础算法学习笔记(状态空间)
基础算法学习笔记(状态空间) 一.状态空间 1.定义(什么是状态空间):一个实际问题的各种可能情况构成的集合.(解释:为什么需要算法来和程序来处理问题?如果一道题可以手算得到答案,换句话说就是存在通过 ...
- Python最优化算法学习笔记(Gurobi)
微信公众号:数学建模与人工智能 github地址:https://github.com/QInzhengk/Math-Model-and-Machine-Learning Python最优化算法学习笔 ...
- 数据结构与算法学习笔记——链栈
数据结构与算法学习笔记(C语言) 链栈 在开始链栈的学习之前,我们先实现一下上一篇文章中提到的检查括号匹配的小程序,鉴于水平有限,本人就随便写一下代码好了,目标仅限于对功能的实现. /*用顺序栈这种数 ...
- 区块链学习笔记15——ETH状态树
区块链学习笔记15--ETH状态树 学习视频:北京大学肖臻老师<区块链技术与应用> 笔记参考:北京大学肖臻老师<区块链技术与应用>公开课系列笔记--目录导航页 引入 要实现的功 ...
- 数据结构与算法学习笔记15:最大流问题 / 二分图 / 有权无权二分图的匹配 / 匈牙利算法 / 银行家算法 / 稳定婚配
数据结构与算法学习笔记15:最大流问题 / 二分图 / 有权无权二分图的匹配 / 匈牙利算法 / 银行家算法 / 稳定婚配 引入小题:最短路径 最大流问题(maximum flow problem) ...
- Parse算法学习笔记
Parse算法学习笔记 Parse算法是一种自底向上的语法分析算法,其主要应用于编译器中的语法分析阶段.相比于其他语法分析算法,Parse算法具有简单.高效的特点.本篇文章将详细介绍Parse算法的原 ...
最新文章
- ATS无法缓存QQ音乐的音频文件问题
- 设计模式——创建型模式
- Windows事件等待学习笔记(二)—— 线程等待与唤醒
- Vue——Vue-Router的push和replace方法[Uncaught (in promise) Error]解决方案
- 关于如何将轮播图在移动端和pc端自适应的操作
- 红帽企业linux4参考指南读书笔记-GRUB引导器
- 3D重建传统算法对比深度学习,SFU谭平:更需要的是二者的融合
- bat执行java文件_.bat文件执行java程序
- 顺序表查找及其优化(Java)
- 阶段3 1.Mybatis_09.Mybatis的多表操作_6 分析mybatis多对多的步骤并搭建环境
- GridView中如何取得隐藏列的值
- 24点之5 7 7 11
- 实现1.1、1.1.1的多级编号文档排版
- 使用react 写一个 仿淘宝 图片放大镜效果
- 关于灰色关联分析以及灰色预测初步理解
- 步进电动机速度调节和方向控制实验
- 《Splunk智能运维实战》——1.2 索引文件和目录
- 百度API提交Java版,让你的网站快速收录提高排名
- 古代艺术家签合同,都狡猾着呢
- Vue.js 电话验证规则(包括座机,带区号和不带区号,手机)