画家问题(关灯问题)
2016-08-05 19:51
295 查看
在openjudge和poj上都有的一道题,枚举问题中很基础的一道题
总时间限制: 1000ms 内存限制: 65536kB
描述
有一个正方形的墙,由N*N个正方形的砖组成,其中一些砖是白色的,另外一些砖是黄色的。Bob是个画家,想把全部的砖都涂成黄色。但他的画笔不好使。当他用画笔涂画第(i, j)个位置的砖时, 位置(i-1, j)、 (i+1, j)、 (i, j-1)、 (i, j+1)上的砖都会改变颜色。请你帮助Bob计算出最少需要涂画多少块砖,才能使所有砖的颜色都变成黄色。
输入
第一行是一个整数n (1≤n ≤15),表示墙的大小。接下来的n行表示墙的初始状态。每一行包含n个字符。第i行的第j个字符表示位于位置(i,j)上的砖的颜色。“w”表示白砖,“y”表示黄砖。
输出
一行,如果Bob能够将所有的砖都涂成黄色,则输出最少需要涂画的砖数,否则输出“inf”。
样例输入
5
wwwww
wwwww
wwwww
wwwww
wwwww
样例输出
15
来源
poj 1681
直接枚举肯定会超时,注意到按照行的顺序枚举,第一行的操作唯一确定了后面几行的合法操作,所以采用枚举第一行操作的思路。第一次做使用位运算做,效率较高。第二次做到时候为了节省代码量采用了一种虚拟边框的方法,,也没有使用位运算而直接储存,故效率不如第一版。本题也可以用异或方程组,但是实现困难,而且最后对解的自由维度也必须枚举,复杂度上并没有优势,加上代码复杂度较高,而且我高斯消元不熟练所以没有写。
以下为代码
version 1
Accepted 256kB 100ms 1086 B
version 2
Accepted 260kB 170ms 1012 B G++
总时间限制: 1000ms 内存限制: 65536kB
描述
有一个正方形的墙,由N*N个正方形的砖组成,其中一些砖是白色的,另外一些砖是黄色的。Bob是个画家,想把全部的砖都涂成黄色。但他的画笔不好使。当他用画笔涂画第(i, j)个位置的砖时, 位置(i-1, j)、 (i+1, j)、 (i, j-1)、 (i, j+1)上的砖都会改变颜色。请你帮助Bob计算出最少需要涂画多少块砖,才能使所有砖的颜色都变成黄色。
输入
第一行是一个整数n (1≤n ≤15),表示墙的大小。接下来的n行表示墙的初始状态。每一行包含n个字符。第i行的第j个字符表示位于位置(i,j)上的砖的颜色。“w”表示白砖,“y”表示黄砖。
输出
一行,如果Bob能够将所有的砖都涂成黄色,则输出最少需要涂画的砖数,否则输出“inf”。
样例输入
5
wwwww
wwwww
wwwww
wwwww
wwwww
样例输出
15
来源
poj 1681
直接枚举肯定会超时,注意到按照行的顺序枚举,第一行的操作唯一确定了后面几行的合法操作,所以采用枚举第一行操作的思路。第一次做使用位运算做,效率较高。第二次做到时候为了节省代码量采用了一种虚拟边框的方法,,也没有使用位运算而直接储存,故效率不如第一版。本题也可以用异或方程组,但是实现困难,而且最后对解的自由维度也必须枚举,复杂度上并没有优势,加上代码复杂度较高,而且我高斯消元不熟练所以没有写。
以下为代码
version 1
Accepted 256kB 100ms 1086 B
#define INF 225 #include<stdio.h> long int row[16]={0},record[15]={0}; int n,minStep=INF,step; int get(int m,int j) { if (j==-1 || j==n) return 0; else return (m&(1<<j))>>j; } void readIn() { char ch; int i=0,j=0; scanf("%d\n",&n); while (i<n) { scanf("%c",&ch); if (ch=='w' || ch=='y') { row[i]|=((ch=='w')<<j); j=((j==n-1)?i++,0:j+1); } } } int main() { readIn(); for (int m=0;m<(1<<n);m++) { for (int i=0;i<n;i++) record[i]=row[i]; step=0; for (int j=0;j<n;j++) step+=get(m,j); for (int j=0;j<n;j++) row[0]^=(get(m,j-1)^get(m,j)^get(m,j+1))<<j; for (int j=0;j<n;j++) row[1]^=(get(m,j))<<j; for (int i=1;i<n;i++) { for (int j=0;j<n;j++) step+=get(row[i-1],j); for (int j=0;j<n;j++) row[i]^=(get(row[i-1],j-1)^get(row[i-1],j)^get(row[i-1],j+1))<<j; for (int j=0;j<n;j++) row[i+1]^=(get(row[i-1],j))<<j; row[i-1]=0; } if (row[n-1]==0 && step<minStep) minStep=step; for (int i=0;i<n;i++) row[i]=record[i]; } if (minStep==INF) printf("inf\n"); else printf("%d\n",minStep); return 0; }
version 2
Accepted 260kB 170ms 1012 B G++
#define MAX_N 15 #define INF 0x7FFFFFFF #include<stdio.h> const int dir[5][2]={{0,0},{1,0},{0,1},{-1,0},{0,-1}}; int state[MAX_N+1][MAX_N+1],map[MAX_N+1][MAX_N+1]; int n,min=INF; char ch; void print(int i,int j) { for (int d=0;d<=4;d++) state[i+dir[d][0]][j+dir[d][1]]^=1; return; } void deal_row(int k,int total) { if (k==n+1) { for (int j=1;j<=n;j++) if (state [j]==0) return; if (total<min) min=total; return; } for (int i=1;i<=n;i++) if (state[k-1][i]==0) { total++; print(k,i); } deal_row(k+1,total); return; } int main() { scanf("%d\n",&n); for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) { scanf("%c",&ch); map[i][j]=(ch=='y'); } scanf("\n"); } for (int state_code=0;state_code!=(1<<n);state_code++) { for (int i=1;i<=n;i++) state[0][i]=(state_code>>(i-1))&1; for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) state[i][j]=map[i][j]; deal_row(1,0); } if (min==INF) printf("inf\n"); else printf("%d\n",min); return 0; }
相关文章推荐
- POJ2411 Mondriaan's Dream(状态压缩)
- POJ 2299 Ultra-QuickSort (求逆序数:离散化+树状数组或者归并排序求逆序数)
- shell命令
- js,jq获取select下拉框的各项值
- 离散数学之把妹要诀
- PHP Date() 函数详细参数
- hdu 5791 dp
- HDOJ 2647 Reward
- 文件缓存与内存缓存
- Android进阶系列0—View的工作流程:measure,layout,draw小结
- Rxjava +Retrofit 你需要掌握的几个技巧,Retrofit缓存,RxJava封装,统一对有无网络处理,异常处理, 返回结果问题
- java float
- opencv 中关于BOW模型的实现以及相关的函数解释
- Rxjava +Retrofit 你需要掌握的几个技巧,Retrofit缓存,RxJava封装,统一对有无网络处理,异常处理, 返回结果问题
- 24种设计模式的体验
- QT中文处理--Qt5对付中文真好用
- android沉浸式文章集锦
- Java &和&& ||与| 的区别
- js 动态表格添加一行删除一行
- 2016多校联合训练赛 第五场1011 Two hdu5791