• $Luogu$ $P2622$ 关灯问题 $mathrm{II}$


    链接

    背景

    (freshwater)(Luogu) (P2622)

    题意

    给定 (n) 盏灯,一开始全都是开着的。有 (m) 种操作,每种操作形如一个长为 (n) 序列 (a)(a_i) 表示第 (i) 盏灯进行的操作: (a_i=1) 表示把第 (i) 盏灯关掉, (a_i=-1) 表示把第 (i) 盏灯打开,否则什么也不做。求使得所有灯都关上的最小操作次数。

    解法

    从朴素解法开始:由于 (n leqslant 10) ,所以所有的灯可以从左往右压成一个 (n) 位的二进制数(显然该数不超过 (1024) )。
    每个操作 (i) 其实可以压成两个二进制数 (t_{i,1}=2^n-1,t_{i,2}=0) ,具体做法是考虑进行的操作的本质:遇到 (a_j=1) 的就把 (t_{i,1}) 二进制表示下的第 (j) 位变成 (0)(x wedge 0=0) ),遇到 (a_j=-1) 的就把 (t_{i,2}) 二进制表示下的第 (j) 位变成 (1)(x vee 1=1) )。则对于一个灯的状态 (x) 进行操作 (i) 之后的状态就是 ((x wedge^{[1]} t_{i,1}) vee^{[2]} t_{i,2}) 。然后 (dfs) 即可。然后你就会获得 (50pts) 的好成绩。
    考虑优化:显然每个灯的状态都不会经过超过 (1) 次,于是可以给经过的状态打个标记。然后你就会获得 (70pts) 的好成绩。下载数据,容易发现无法判断无解。

    (trick)

    考虑换一种搜索方法。
    可以考虑用步数作为搜索的阶段,也即搜索树的深度。不妨换用 (bfs) ,每次只把没走过的合法的状态推进队列。若队列为空时仍未更新答案则判定无解即可。

    细节

    写之前一定要想清楚转移的设计,要敲定所有细节,否则调试会很麻烦。

    代码

    $View$ $Code$ ```cpp #include using namespace std; inline int read() { int ret=0,f=1; char ch=getchar(); while(ch>'9'||ch<'0') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { ret=(ret<<1)+(ret<<3)+ch-'0'; ch=getchar(); } return ret*f; } int n,m,x,t[105][2],ans=101; bool vis[2055]; queue > q; inline void bfs() { q.push(make_pair((1< -------------------------------- $[1]$ : $wedge$ 表示逻辑与运算。 $[2]$ : $vee$ 表示逻辑或运算。
  • 相关阅读:
    ES6-10笔记(class类)
    ES6-10笔记(let&const -- Array)
    小程序的表单提交
    小程序表单回显
    小程序template模板的使用和模板多数据传递
    微信小程序的初始配置
    babel 版本原因运行报错,解决办法
    webpack 和 webpack-cli 安装和使用中出现的问题
    jQuery中操作属性的方法attr与prop的区别
    javaScript 添加和移除class类名的几种方法
  • 原文地址:https://www.cnblogs.com/Peter0701/p/11723086.html
Copyright © 2020-2023  润新知