【POJ 3279 Fliptile】开关问题,模拟

题目链接:http://poj.org/problem?id=3279

题意:给定一个n*m的坐标方格,每个位置为黑色或白色。现有如下翻转规则:每翻转一个位置的颜色,与其四连通的位置都会被翻转,但注意只扩散一圈,不是连锁反应

求最少翻转几个位置能够使所有n*m个位置都变为白色。若有解,求字典序最小的翻转方案(给出每个位置的翻转次数)。

数据范围:n, m 属于 [1, 15]

思路:我们把翻转方案中的翻转称为“主动翻转”,翻转过程中受邻居影响而发生的翻转称为“被动翻转”。观察例子可得出如下几个结论:

  1. 最优解中,每个位置的主动翻转不超过1次。

  2. 各个位置翻转的次序对结果没有影响。

  3. 某一时刻,位置(i, j)的颜色取决于到目前为止它的主动翻转和被动翻转次数之和,记为cnt;具体地,由结论1可推得cnt为奇数则变色,偶数则不变色。

  4. 位置(i, j)的被动翻转次数 = 与它四连通的位置的主动翻转次数之和。

解法:首先枚举第一行的所有可能的翻转动作,这里由于m <= 15,所以用一个整型实现“状态压缩”,即枚举所有 i 属于[0, 2m-1], i 的二进制展开的第 j 位代表原图第一行第 j 个位置是否主动翻转。

然后,由结论2、3,可对每个第一行的枚举值从第二行开始自上而下逐行递推:第 i-1 行通过第 i 行垂直位置的主动翻转而“修正”;具体地,对于位置(i, j),考查位置(i-1, j),若(i-1, j)为黑色,则目前一定要对(i, j)主动翻转才能带动(i-1, j)被动翻转为白色。这样的修正持续到最后一行,由于没有下一行可以修正最后一行,因此可直接判最后一行是否为全白,若不是则无解。

最后,对于最优解的维护,这里用二维数组b直接记录每个位置进行的主动翻转的次数。由结论3、4,可以通过数组b在O(1)时间内算出当前某个位置的颜色,以便判断是否需要修正。

解法和代码参照了http://blog.csdn.net/ac_hell/article/details/51077271 以及 http://blog.csdn.net/ac_hell/article/details/51077320,写得很清楚,学习了。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 using namespace std;
 5 const int MAX_N = 16;
 6 const int MAX_M = 16;
 7 const int INF = 0x7fffffff;
 8 int a[MAX_N][MAX_M];//原图
 9 int b[MAX_N][MAX_M];//此位置共翻转了几次
10 int c[MAX_N][MAX_M];//最优解
11 int n, m;
12 int dx[] = {0, 0, 0, 1, -1}, dy[] = {1, -1, 0, 0, 0};
13
14 bool out(int x, int y){
15     if(x < 0 || x >=n || y < 0 || y >= m) return true;
16     return false;
17 }
18
19 int get_color(int x, int y){
20     int color = a[x][y];
21     for(int i=0; i<5; i++){
22         int nx = x + dx[i], ny = y + dy[i];
23         if(out(nx, ny)) continue;
24         color += b[nx][ny];//主动+被动
25     }
26     return color & 1;
27 }
28
29 int flip(int s){
30     for(int i=1; i<=m; i++){
31         b[0][i-1] = (s>>(m-i)) & 1;
32         //printf("%d ", b[0][i-1]);
33     }
34     for(int i=1; i<n; i++){
35         for(int j=0; j<m; j++){//(i-1, j)想变,必须让(i, j)翻转
36             if(get_color(i-1, j)){
37                 b[i][j] = 1;
38                 //printf("%d, %d\n", i, j);
39             }
40         }
41     }
42     for(int i=0; i<m; i++){
43         if(get_color(n-1, i)){
44             //printf("%d no\n", i);
45             return INF;
46         }
47
48     }
49     int times = 0;
50     for(int i=0; i<n; i++){
51         for(int j=0; j<m; j++){
52             times += b[i][j];
53         }
54     }
55     return times;
56 }
57
58 int main()
59 {
60     freopen("3279.txt", "r", stdin);
61     scanf("%d%d", &n, &m);
62     for(int i=0; i<n; i++){
63         for(int j=0; j<m; j++){
64             scanf("%d", &a[i][j]);
65         }
66     }
67     int ans = INF;
68     for(int i=0; i< (1<<m); i++){//信号量集
69         memset(b, 0, sizeof(b));//翻转方案
70         int t = flip(i);
71         if(t < ans){
72             ans = t;
73             memcpy(c, b, sizeof(b));//更新最优解
74         }
75     }
76     if(ans == INF) printf("IMPOSSIBLE\n");
77     else{
78         for(int i=0; i<n; i++){
79             for(int j=0; j<m; j++){
80                 printf("%d ", c[i][j]);
81             }
82             printf("\n");
83         }
84     }
85     return 0;
86 }

本来是做今天的计蒜之道的热身赛A题,与这道同类型。比赛时不会,然而比赛结束后已不能提交。。。

时间: 2024-09-04 10:17:02

【POJ 3279 Fliptile】开关问题,模拟的相关文章

poj 1828 Monkeys&amp;#39; Pride 模拟

   排个序,模拟下就好了,水题一个 /* author:jxy lang:C/C++ university:China,Xidian University **If you need to reprint,please indicate the source** */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algori

UVa 755 / POJ 1002 487--3279 (排序)

755 - 487--3279 Time limit: 3.000 seconds http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=98&page=show_problem&problem=696 http://poj.org/problem?id=1002 Businesses like to have memorable telephone numbers. On

【POJ 3009 Curling2.0 迷宫寻径 DFS】

http://poj.org/problem?id=3009 模拟冰壶的移动,给出到达终点的最少投掷次数(不可达时为-1). 具体移动规则如下: 每次选四个方向之一,沿此方向一直前进,直到撞到block或出界或抵达目标位置. 如果撞到block,冰壶停在block的前一个位置,block消失,此时可改变冰壶的移动方向(重新投掷一次): 如果出界,则这条移动路径以失败结束: 如果抵达目标位置,则记录这条移动路径一共投掷的次数. 投掷次数不超过10次的为成功路径. 如果存在成功路径,输出最少的投掷次

支付宝体验设计精髓. 02 无规矩不成方圆

02 无规矩不成方圆 -设计规范的建设 文/ 周建波.朱兰民 第1节 规矩成就方圆 孟子曰:离娄之明,公输子之巧,不以规矩,不能成方圆.-<孟子> 设计规范是用户体验的最低标准!-吴明 支付宝作为一个大型的"生活服务类平台",既有官方自营应用,也有第三方接入应用,数十个应用共计数百个页面,并且还在不断发展壮大.我们将支付宝定义为一个系统级的应用一点儿都不夸张,其复杂度已经逼近一个完整的"生态系统". 在这样一个系统级的应用中,我们面临的设计挑战相当复杂:

支付宝体验设计精髓

支付宝体验设计精髓 支付宝AUX团队 著 吴明  主编 图书在版编目(CIP)数据 支付宝体验设计精髓/支付宝AUX团队著. -北京:机械工业出版社,2016.9 ISBN 978-7-111-54888-1 I. 支- II. 支- III. 电子商务―支付方式―研究 IV. F713.361.3 中国版本图书馆CIP数据核字(2016)第226108号 支付宝体验设计精髓 出版发行:机械工业出版社(北京市西城区百万庄大街22号 邮政编码:100037) 责任编辑:孙海亮 责任校对:董纪丽 印

《仿人机器人原理与实战》一1.4 反射弧实验进阶

1.4 反射弧实验进阶 在仿人机器人的设计中,这种简单的反射弧模拟装置不仅功能齐全而且十分有用.同人类的反射一样,直至反射被触发,舵机才正常运转.不过,你可以将程序稍作改进,以便提供更多有实用价值的功能.按照如下顺序,我们将这些功能添加到模拟器的硬件和代码库中. 1.4.1 反射方向 第一个改进是以编程方式定义反射方向.如果把开关S1安装在舵机摇臂上,那么反射可以使按钮的运动方向朝向或躲避撞击物体.如果反射方向不能满足设计要求,那么你可以移动开关,或者减小位置变量的值至0.以下是需要替换的递增代

POJ 3371 Flesch Reading Ease (模拟题)

Flesch Reading Ease:http://poj.org/problem?id=3371 题目很水,就是看懂题就行. 题意: 给出一篇规范的文章,求其 句子数.单词数 和 音节数把这3个值代入题目给出的公式,输出其结果,保留2位小数. 标记单词分隔符: 逗号(,) 和 空格( ) 句子分隔符:句号(.) 问号(?) 冒号(:) 分号(;) 感叹号(!) 音节处理要求: (1)当单词总长度<=3时,音节数无条件+1 (2) 当单词总长度>3时,单词中每出现一个元音字母(a.e.i.o

POJ 3792 Area of Polycubes:模拟

POJ 3792:http://poj.org/problem?id=3792 大意: 按顺序给你一堆正方体,如果当前输入的正方体上下左右前后都没有跟之前的正方体有连接,就输出NO,并输出当前是第几个.如多每次输入的正方体跟之前的都有连接,那么最后输出组成的几何体的表面积. 思路:一步一步模拟就行.注意:1.要判一下有重复的输入,如果有重复的输入,要输出NO,并输出第几..2.注意下标不要向下溢出. 更多精彩内容:http://www.bianceng.cnhttp://www.bianceng

POJ 1835 宇航员:模拟&amp;amp;三维向量旋转

Description 问题描述: 宇航员在太空中迷失了方向,在他的起始位置现在建立一个虚拟xyz坐标系,称为绝对坐标系,宇航员正面的方向为x轴正方向,头顶方向为z轴正方向,则宇航员的初始状态如下图所示: 现对六个方向分别标号,x,y,z正方向分别为0,1,2,负方向分别为3,4,5:称它们为绝对方向.宇航员在宇宙中只沿着与绝对坐标系xyz轴平行的方向行走,但是他不知道自己当前绝对坐标和自己面向的绝对方向. 任务描述: 请根据宇航员对自己在相对方向上移动的描述确定宇航员最终的绝对坐标和面向的绝对