1815:画家问题

简介: 题目链接:NOI题库: http://noi.openjudge.cn/ch0201/1815/poj 1681: http://poj.org/problem?id=1681 总时间限制: 1000ms内存限制: 65536kB描述有一个正方形的墙,由N*N个正方形的砖组成,其中一些砖是白色的,另外一些砖是黄色的。

题目链接:

NOI题库: http://noi.openjudge.cn/ch0201/1815/

poj 1681: http://poj.org/problem?id=1681

 

总时间限制: 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 

算法分析:

这个题目有些像熄灯问题,解法也是利用了熄灯问题中第一行的选择决定下一行的选择。所以只需要枚举出第一行所有的操作方案,以及验证最后一行是否正确。

大体思路:枚举第一行的所有可能的操作方案。对每一个方案都要统计一下该方案需要涂的方块数目并检验该方案能否使得所有的方块最后都变为黄色。检验方法就是扫描最后一行是否剩余白色块即可。

代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<limits.h>
 4 
 5 int n;
 6 char src[18][18],temp1[18][18];
 7 int dx[4]={-1,0,1,0};//上右下左 
 8 int dy[4]={0,1,0,-1};
 9 
10 int GetBit(int c,int i)//取c的第i位。i从0开始。 
11 {  return ( c >> i ) & 1;  }
12 void Flip(int i,int j)//将src[i][j]及其周围元素取反 
13 {
14     int k,x,y;
15     src[i][j]=src[i][j]=='w'?'y':'w';
16     for(k=0;k<4;k++)
17     {
18         x=i+dx[k];
19         y=j+dy[k];
20         if(x>=0&&x<n&&y>=0&&y<n)
21         {
22             src[x][y]=src[x][y]=='w'?'y':'w';
23         }
24     }
25 }
26 int main(int argc, char *argv[])
27 {
28     int i,j,k,t;
29     char str[20];
30     int count,min=INT_MAX;
31 
32     scanf("%d",&n);
33     for(i=0;i<n;i++)
34     {
35         scanf("%s",str);
36         for(j=0;j<n;j++)
37         {
38             temp1[i][j]=src[i][j]=str[j];
39         }
40     }
41     
42     t=(1<<n);//第0行总共有2^n种不同的涂法 
43     for(i=0;i<=t;i++)//枚举所有涂法,对每一种涂法都统计该方案需要涂的数量并检验该方案能否全变为y。 
44     {
45         memcpy(src,temp1,sizeof(src));
46         /*for(k=0;k<n;k++)
47             for(j=0;j<n;j++)
48                 src[k][j]=temp1[k][j];*/
49         count=0;
50         
51         for(j=0;j<n;j++)//根据当前方案i各个比特的值去涂第0行 
52         {
53             if(GetBit(i,j)==1)//获取i的第j个比特。若为1,则需要涂(0,j)位置 
54             {
55                 Flip(0,j);
56                 count++;
57             } 
58         }
59         for(k=1;k<n;k++)//扫描除了第0行以外的所有行 
60         {
61             for(j=0;j<n;j++)
62             {
63                 if(src[k-1][j]=='w')
64                 {
65                     Flip(k,j);
66                     count++;
67                 }
68             }
69         }
70         for(j=0;j<n;j++)//扫描最后一行检查是否有未变为y的单元 
71         {
72             if(src[n-1][j]=='w') break;
73         }
74         if(j==n&&count<min) min=count;
75     }
76     if(min==INT_MAX) printf("inf\n");
77     else printf("%d\n",min);
78     return 0;
79 }

poj提交的代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<limits.h>
 4 
 5 int n;
 6 char src[18][18],temp1[18][18];
 7 int dx[4]={-1,0,1,0};//上右下左 
 8 int dy[4]={0,1,0,-1};
 9 
10 int GetBit(int c,int i)//取c的第i位。i从0开始。 
11 {  return ( c >> i ) & 1;  }
12 void Flip(int i,int j)//将src[i][j]及其周围元素取反 
13 {
14     int k,x,y;
15     src[i][j]=src[i][j]=='w'?'y':'w';
16     for(k=0;k<4;k++)
17     {
18         x=i+dx[k];
19         y=j+dy[k];
20         if(x>=0&&x<n&&y>=0&&y<n)
21         {
22             src[x][y]=src[x][y]=='w'?'y':'w';
23         }
24     }
25 }
26 int main(int argc, char *argv[])
27 {
28     int i,j,k,t;
29     char str[20];
30     int count,min=INT_MAX;
31 
32     int T;
33     scanf("%d",&T);
34     for(;T>0;T--)
35     {
36         min=INT_MAX;
37         scanf("%d",&n);
38         for(i=0;i<n;i++)
39         {
40             scanf("%s",str);
41             for(j=0;j<n;j++)
42             {
43                 temp1[i][j]=src[i][j]=str[j];
44             }
45         }
46         
47         t=(1<<n);//第0行总共有2^n种不同的涂法 
48         for(i=0;i<=t;i++)//枚举所有涂法,对每一种涂法都统计该方案需要涂的数量并检验该方案能否全变为y。 
49         {
50             memcpy(src,temp1,sizeof(src));
51             /*for(k=0;k<n;k++)
52                 for(j=0;j<n;j++)
53                     src[k][j]=temp1[k][j];*/
54             count=0;
55             
56             for(j=0;j<n;j++)//根据当前方案i各个比特的值去涂第0行 
57             {
58                 if(GetBit(i,j)==1)//获取i的第j个比特。若为1,则需要涂(0,j)位置 
59                 {
60                     Flip(0,j);
61                     count++;
62                 } 
63             }
64             for(k=1;k<n;k++)//扫描除了第0行以外的所有行 
65             {
66                 for(j=0;j<n;j++)
67                 {
68                     if(src[k-1][j]=='w')
69                     {
70                         Flip(k,j);
71                         count++;
72                     }
73                 }
74             }
75             for(j=0;j<n;j++)//扫描最后一行检查是否有未变为y的单元 
76             {
77                 if(src[n-1][j]=='w') break;
78             }
79             if(j==n&&count<min) min=count;
80         }
81         if(min==INT_MAX) printf("inf\n");
82         else printf("%d\n",min);
83     }
84     return 0;
85 }
View Code

 

相关文章
|
7月前
超简单的html+css魔幻霓虹灯文字特效
超简单的html+css魔幻霓虹灯文字特效
59 3
超简单的html+css魔幻霓虹灯文字特效
逐帧动画案例(奔跑的小人)
逐帧动画案例(奔跑的小人)
250 0
逐帧动画案例(奔跑的小人)
|
数据可视化 前端开发 小程序
中秋节——我给心爱的她做了一个3d月球动画
前言 大家好,又到了周末了,又到了Fly写文章的时候了, 过几天不是中秋节了,想着之前写过一篇从0- 1 实现3D地球的,反响效果特别好, 这次趁着🎑节给大家写了一个月球绕地球的运转的动画。本篇文章还是偏入门级别,重在把简单的知识讲清楚,如果是资深three爱好者,可以直接划走了,不浪费大家时间。ok👌言归正传,读完本篇文章你可以学到什么?至于心爱的她—— 就是学习 本文阅读估计花费 5 分钟 天空盒子的制作 three.js 中的贴图 一个物体绕另一个物体旋转 初始化 这篇文章我不会在从头详细的介绍three.js 的一些要素了,如果小伙伴你不是很清楚的话,你可以直接看下我这篇文章入
中秋节——我给心爱的她做了一个3d月球动画
|
容器
Silverlight & Blend动画设计系列五:故事板(StoryBoards)和动画(Animations)
原文:Silverlight & Blend动画设计系列五:故事板(StoryBoards)和动画(Animations)   正如你所看到的,Blend是一个非常强大的节约时间的设计工具,在Blend下能够设计出很多满意的动画作品,或许他具体是怎么实现的,通过什么方式实现的我们还是一无所知。
948 0
通通玩blend美工(1)——荧光Button
原文:通通玩blend美工(1)——荧光Button   最近老大出差去了,光做项目也有点烦,写点教程消遣消遣(注:此乃初级教程,所以第一个消遣是本人消遣,第二个是指供各位看官消遣...)   看着各位大虾出系列文章貌似挺好玩的,本人耍了2个月的Wpf,有点见解,希望各位看官笑纳。
1057 0
【益智题】寻找一个五角星
从下图中找出一个五角星。。。
1096 0