poj 2813 画家问题(枚举解决一维和二维)
来源:互联网 发布:淘宝实名制更改 编辑:程序博客网 时间:2024/05/19 15:20
给定一种状态集合,通常一个位置仅有一种状态,对其某一位置进行操作可改变其本身及其相邻位置的状态,通过一系列的操作达到目标状态集,并求出其所有可行操作中最少操作数的过程,可以将其归为画家问题。解决画家问题的核心是枚举每个位置的操作状态,并发现之间的联系,找出所有可行的解,然后找到最优解。
一维画家问题(特殊密码锁)
思路分析:从前向后看,对于一个位置,要保证其前面一个一样,只能有一种按法。所以第一次的按法确定后,以后的按法也随之确定,再由最终最后位置是否相同即可判断是否可以。所以枚举第一个是否按,再找到最优解。
#include<iostream>#include<cstring>#include<algorithm>using namespace std;void reverse(char a[31], int i)//翻转{ if (a[i] - '0') a[i] = 0 + '0'; else a[i] = 1 + '0';}int main(){ bool flag = false; char a[32], b[32],h[32];//h用来进行第二次操作,保持原型 memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); cin.getline(a, 32); cin.getline(b, 32); int len = strlen(a); int tmp1 = 0, tmp2 = 0; for (int k = 0; k < 2; k++)//枚举第一个位置是否操作 { memcpy(h, a, sizeof(a)); if (k)//如果按下 { reverse(a, 0); reverse(a, 1);//改变初始状态 tmp1++; for (int i = 1; i < len; i++) { if (a[i - 1] != b[i - 1]) //前面不相等,为使前面相等,该位置翻转 { tmp1++; reverse(a, i); if (i < len - 1) { reverse(a, i + 1); } } if (a[len - 1] == b[len - 1]) flag = true; } } else { for (int i = 1; i < len; i++) { if (h[i - 1] != b[i - 1] { tmp2++; reverse(h, i); if (i < len - 1) { reverse(h, i + 1); } } if (h[len - 1] == b[len - 1]) flag = true; } } } if (flag) { tmp1 = min(tmp1, tmp2); cout << tmp1 << endl; } else { cout << "impossible" << endl; } //system("pause"); return 0;}
将其扩展到二维,即得到画家问题。(poj 2813)
同样是枚举,不同的是空间由一维扩展到了二维,通过类比思想,枚举也应该由一个位置的状态扩展到一行的状态,可通过理解高中时的平面与空间的勾股定理。同样,第一行的状态集合确定了,以后各行的状态集合也确定了。难点在于,一行的状态如何表示,状态转换如何更简便的进行,考虑到其仅有两个状态,而二进制表示中也仅有0和1两种状态,所以可以采取位运算的方式来进行。
#include<iostream>#include<cstring>#include<algorithm>using namespace std;//白色记为1,黄色记为0inline void setbit(short &c, int i, bool v)//将状态转换成二进制表示{ if (v) { c |= (1 << i); } else { c &= ~(1 << i); }}int onecount(short x)//记录1的个数,即所操作的次数{ int c; for (c = 0; x>0; ++c) { x &= x - 1; } return c;}inline void Flip(short & x, int j)//状态转换{ x ^= (1 << j);}inline int getbit(short c, int i)//读取该位置的状态,是否涂色{ return (c >> i) & 1;}int main(){ short originlights[16];//初始输入 short lights[16]; int n; cin >> n; memset(originlights, 0, sizeof(originlights)); for (int i = 0; i<n; i++) { for (int j = 0; j<n; j++) { char c; cin >> c; setbit(originlights[i], j, c != 'y'); } } int sw = 1 << n;//第一行总共的变换情况 int ms; short switchs; int minDraw = 1 << 30; for (ms = 0; ms<sw; ms++) { int totalDraw = 0; switchs = ms; memcpy(lights, originlights, sizeof(originlights)); for (int i = 0; i<n; i++) { totalDraw += onecount(switchs); for (int j = 0; j<n; j++) { if (getbit(switchs, j)) { //本身的行转换 if (j>0) Flip(lights[i], j - 1); Flip(lights[i], j); if (j<n - 1) Flip(lights[i], j + 1); } } if (i<n - 1) lights[i + 1] ^= switchs; //转换下一行,异或操作 switchs = lights[i]; //为使得本行全部置换,下一行置换状态与本行状态相同 } if (lights[n - 1] == 0) { minDraw = min(minDraw, totalDraw); } } if (minDraw == 1 << 30) { cout << "inf" << endl; } else cout << minDraw << endl; return 0;}
再次改变目标状态,分别得到两种目标,得到最优解,即为Flip Game(poj 1753),随后会在广搜中给出。
谢谢大家阅读,限于水平有限,代码效率低下,望各位巨巨指正。
0 0
- poj 2813 画家问题(枚举解决一维和二维)
- poj 2813 画家问题(枚举局部)
- 连续子数组的最大和问题(一维和二维)To the Max (POJ 1050)
- 最接近点对(一维和二维)
- java 一维和二维数组的拷贝问题
- 关于一维和二维数组名是指针的问题
- 一维和二维树状数组
- 枚举—案例(画家问题poj1681)
- 枚举 画家问题
- 画家问题--枚举方法
- 数组(一维和二维)与指针(C语言)
- nyoj 289 苹果(01背包一维和二维实现)
- 树状数组的模板(一维和二维)
- C语言如何动态申请空间(一维和二维)
- poj 1681 画家问题
- POJ画家问题
- POJ 1681 画家问题
- JSON定义一维和二维数组格式
- js 判断字符串是否包含某字符串,String对象中查找子字符indexOf,查找字符串出现的次数split
- java中常用的设计模式
- 【报错】BatchUpdateException: Data truncation: Data too long
- C++ 对象的内存布局(多重虚拟继承)
- mysql消除重覆记录
- poj 2813 画家问题(枚举解决一维和二维)
- Hibernate技术文档
- ibatis中使用like模糊查询
- Qt使用MinGW编译,如何忽略警告
- 发布给用户的apk没有签名如何升级?
- http报文学习笔记
- android进行异步更新UI的四种方式
- spark createDirectStream保存kafka offset(JAVA实现)
- javascript中encodeURI和decodeURI方法