穷举(四):POJ上的两道穷举例题POJ 1411和POJ 1753

      下面给出两道poj上的问题,看如何用穷举法解决。

calling extraterrestrial intelligence again

description

a message from humans to extraterrestrial intelligence was sent through the arecibo radio telescope in puerto rico on the afternoon of saturday november 16, 1974. the message consisted of 1679 bits and was meant to be translated to a rectangular picture with 23 x 73 pixels. since both 23 and 73 are prime numbers, 23 x 73 is the unique possible size of the translated rectangular picture each edge of which is longer than 1 pixel. of course, there was no guarantee that the receivers would try to translate the message to a rectangular picture. even if they would, they might put the pixels into the rectangle incorrectly. the senders of the arecibo message were optimistic.

we are planning a similar project. your task in the project is to find the most suitable width and height of the translated rectangular picture. the term "most suitable" is defined as follows. an integer m greater than 4 is given. a positive fraction a/b less than or equal to 1 is also given. the area of the picture should not be greater than m. both of the width and the height of the translated picture should be prime numbers. the ratio of the width to the height should not be less than a/b nor greater than 1. you should maximize the area of the picture under these constraints.

in other words, you will receive an integer m and a fraction a/b. it holds that m 4 and 0 a/b = 1. you should find the pair of prime numbers p, q such that pq = m and a/b = p/q = 1, and furthermore, the product pq takes the maximum value among such pairs of two prime numbers. you should report p and q as the "most suitable" width and height of the translated picture.

input

the input is a sequence of at most 2000 triplets of positive integers, delimited by a space character in between. each line contains a single triplet. the sequence is followed by a triplet of zeros, 0 0 0, which indicates the end of the input and should not be treated as data to be processed.

the integers of each input triplet are the integer m, the numerator a, and the denominator b described above, in this order. you may assume 4 m = 100000 and 1 = a = b = 1000.

output

the output is a sequence of pairs of positive integers. the i-th output pair corresponds to the i-th input triplet. the integers of each output pair are the width p and the height q described above, in this order.

each output line contains a single pair. a space character is put between the integers as a delimiter. no other characters should appear in the output.

sample input

5 1 2

99999 999 999

1680 5 16

1970 1 1

2002 4 11

0 0 0

sample output

2 2

313 313

23 73

43 43

37 53

      编程思路。

      对于输入的m,通过穷举找到一组质数对,满足条件:1)p、q均为质数,且p =q =m;2)p*q =m;3)a/b = p/q;4)p*q取得最大值。

      首先确定p和q的穷举范围,由于m不超过100000,因此p和q不会超过50000。进一步考虑,由于1 =a =b =1000,所以a/b的最小值为1/1000=0.001,因此,p/q =0.001。而当m达到最大100000时,100000/11=9090.9,质数2、3、5、7除以9091均小于0.001,因此,可将p、q的范围进一步缩小到取2~9091之间的质数。

      先将小于9092的所有质数求出来,并存放在数组prime中,记下质数的个数num。

      用二重循环穷举所有的p、q组合,对每种组合去判断是否符合条件,如果满足,将p*q与当前最大值max比较,保存最大的p*q。

      源程序。

#include iostream

using namespace std;

int main

{

  int flag[9092]={0},prime[5000]={0};

  int num=0,m,a,b,p,q,max,i,j;

  double s;

  for

  { 

  if

  {

  prime[num++]=i;

  for

  flag[j]=1;

  }

  }

  cin m a b;

  while

  { 

  max=0;

  s=1.0*a/b;

  for

  { 

            if break;

  for

  {

    if

    break;

                         if

    { 

                                  max=prime[i]*prime[j];

                                  p=prime[i];

                                  q=prime[j];

    }

                   }

           }

  cout p " " q endl;

  cin m a b;

  }

  return 0;

}

 

flip game

description

flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. one side of each piece is white and the other one is black and each piece is lying either it's black or white side up. each round you flip 3 to 5 pieces, thus changing the color of their upper side from black to white and vice versa. the pieces to be flipped are chosen every round according to the following rules:

1. choose any one of the 16 pieces.

2. flip the chosen piece and also all adjacent pieces to the left, to the right, to the top, and to the bottom of the chosen piece .

consider the following position as an example:

bwbw

wwww

bbwb

bwwb

here "b" denotes pieces lying their black side up and "w" denotes pieces lying their white side up. if we choose to flip the 1st piece from the 3rd row , then the field will become:

bwbw

bwww

wwwb

wwwb

the goal of the game is to flip either all pieces white side up or all pieces black side up. you are to write a program that will search for the minimum number of rounds needed to achieve this goal.

input

the input consists of 4 lines with 4 characters "w" or "b" each that denote game field position.

output

write to the output file a single integer number - the minimum number of rounds needed to achieve the goal of the game from the given position. if the goal is initially achieved, then write 0. if it's impossible to achieve the goal, then write the word "impossible" .

sample input

bwwb

bbwb

bwwb

bwww

sample output

4

     编程思路1。

      因为任何一个格子翻偶数次和翻0次的效果是一样的,翻奇数次和翻1次的效果也是一样的。因此,一个格子要么翻1次,要么不翻。另外翻格子的顺序对最终的结果是没有影响的,也就是说先翻一号格子再翻二号格子和先翻二号格子再翻一号格子的效果是一样。

      这样,可以对十六个格子中的每个格子翻或不翻两种情况进行穷举,总的穷举次数为216=65536次。

用一个一维数组int bits[16]来保存16个格子的初始状态,黑色的格子置为1,白色的置为0。则题目中图示的状态可描述为bits[16]={ 1,0,1,0,0,0,0,0,1,1,0,1,1,0,0,1}。

题目图示翻转格子bits[8],需进行操作

bits[8]=!bits[8]=0, 

bits[4]=!bits[4]=1, 

bits[9]=!bits[9]=0, 

bits[12]=!bits[12]=0, 

由于格子8处于最左边,它的左边没有格子,因此bits[i - 1] = !不能操作。

这样,翻转格子8后,状态变为{ 1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,1}。

用变量mincnt记录所需的最小的翻格子个数,初始值设为17,因为最多翻16个格子。

      用循环 for对16个格子的翻或不翻的组合情况进行穷举。对每种情况i,判断i对应的二进制数中的第j位是否为1,如果为1,则翻转格子j。一种组合情况翻转完成后,判断当前状态是否为纯色,如果是,记录所翻转格子数的最小值。

      源程序1。

#include iostream

using namespace std;

// 判断当前格局是否为纯色

int issolidcolor

{

  int i = 0;

  for

  if

  return 0;

  return 1;

}

// 改变第i个格子及其周围格子的颜色编程思路2。

      在上面的思路1中,用数组bits[16]来保存一种格局。实际上,可以用一个0~65535之间的整数value来保存一种格局。该整数value对应的16个二进制数位中为1的位j代表格子j是黑色。由于一个16位的二进制数从低位到高位的权值依次为1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,因此,将一种格局映射为value值可用一个简单循环来实现:

  char c;

  for

  {

  cin c;

  if

  value += bitval[i];

  }

      其中,int bitval[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};

      例如,题目图示所给出的格局映射为的value值为39685,对应二进制数为1001101100000101。即39685=32768+4096+2048+512+256+4+1。

      翻转一个格子是将它及其周围的格子翻转,可以看成对应二进制位变反。将一个整数的某个二进制位变反可以通过对该位用1进行异或运算实现。因此,对于当前的格局value,若要翻转某个格子i,只需将value异或一个特定的整数c[i]即可。

      例如,按题目的格局value,要翻转第8个格子,由于涉及到4个格子的变反,异或的11二进制数值应为1001100010000,及0x1310。

      39685^的值34837,对应二进制数为1000100000010101,转换为格局为

bwbw

bwww

wwwb

wwwb

      用一个数组ctable[16]来保存翻转每个格子应异或的特定整数,该数组初始化为:

          int ctable[16] = {0x13,0x27,0x4e,0x8c,0x131,0x272,0x4e4,0x8c8,0x1310,0x2320,

0x4e40,0x8c80,0x3100,0x7200,0xe400,0xc800};

      同样用循环for对16个格子的翻或不翻的组合情况进行穷举。对于穷举的每组情况,记录每一次使得value == 0||value == 65535的翻格子数,保存翻格子数目最小的数值。

      源程序2。

#include iostream

using namespace std;

int main

{

  int ctable[16] = {0x13,0x27,0x4e,0x8c,0x131,0x272,0x4e4,0x8c8,0x1310,0x2320,

0x4e40,0x8c80,0x3100,0x7200,0xe400,0xc800};

  int bitval[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};

  int i,j,value = 0, chgval;

  int cnt,mincnt = 17;

  char c;

  for

  {

  cin c;

  if

  value += bitval[i];

  }

  for

  {

  cnt = 0;

  chgval = value;

  for

  if

  {

  cnt++;

  chgval ^= ctable[j];

  }

  if

  if   mincnt = cnt;

  }

  if cout "impossible" endl;

  else  cout mincnt endl;

  return 0;

}

      换一种思路穷举。

      前面的两种思路是按0~65535的顺序穷举,这样的顺序所选取的格子数目是不连续的。而题目要得到的是所需翻转的最少的格子数。因此,穷举的顺序最好从格子的数目这一角度出发。即当0个格子被翻转时,看对应的格局是否为纯色;否则选择1个格子进行翻转,看翻转后的格局是否为纯色;否则再选择2个格子进行翻转,看翻转后的格局是否为纯色; ;最后选择16个格子进行翻转。在这个过程中,只要有纯色的格局出现,就结束穷举过程,输出相应的被选择的格子个数。如果16个格子都被翻转了,还是没变成纯色,则输出 impossible 。

因此,这种思路的关键问题是怎样得到从16个格子中选取n个格子的所有组合。

      组合情况的递归实现。

      设将从1~len共len个数中选取count个不同的数,并存放于数组take中的操作抽象为函数void combinetest,则这个操作过程可以采用递归实现:

       在count~len中选择一个数i赋给take[count-1];

       再从1~i共i个数中选取count-1个不同的数,即递归调用combinetest;

       递归结束条件为count==1。

       编写的递归函数如下:

void combinetest

{

  int i,j;

  for

  {

     take[count - 1] = i;

  if

  combinetest;

  else

  {

  for

  {

  cout take[j] "  ";

  }

  cout endl;

  }

  }

}

      编写如下的程序段来测试递归函数combinetest。

  int n,m;

  cin n m;

  int *take = new int [m];

  combinetest;

  delete  [] take;

       运行这段程序,输入5和3,可得到如下所示的结果。

5

3

5  4  3

5  4  2

5  4  1

5  3  2

5  3  1

5  2  1

4  3  2

4  3  1

4  2  1

3  2  1

press any key to continue

      按新思路改写思路1的源程序3。

#include iostream

using namespace std;

// 判断当前格局是否为纯色

int issolidcolor

{

  int i = 0;

  for

  if

  return 0;

  return 1;

}

// 改变第i个格子及其周围格子的颜色按新思路改写思路2的源程序4。

#include iostream

using namespace std;

int ctable[16] = {0x13,0x27,0x4e,0x8c,0x131,0x272,0x4e4,0x8c8,0x1310,0x2320,

0x4e40,0x8c80,0x3100,0x7200,0xe400,0xc800};

int bitval[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};

void combine

{

  int i,j,chgval;

  for

  {

  if   break;

     take[count - 1] = i - 1;

  if

  combine;

  else

  {

  chgval = value;

  for

  chgval ^= ctable[take[j]];

  if

  cnt = num;

  }

  }

}

int main

{

  int i,j,cnt,value = 0;

  char c;

  for

  {

  cin c;

  if

  value += bitval[i];

  }

  if

  cout 0 endl;

  else

  {

  for

  {

  cnt = 0;

  int *take = new int [j];

  combine;

  if

    {

  cout cnt endl; 

    delete  [] take;

  break;

    }

  delete  [] take;

  }

  if

   cout "impossible" endl;

  }

  return 0;

}

      将上述四个源程序依次提交到poj,可得到如图1所示的结果。由图可以看出,源程序4的执行效率最好。

 

图1  poj显示的解决 问题1753 的四种源程序的评判情况

新闻聚焦
猜你喜欢
热门推荐
  • Maya怎么建模稻草人模型?

    Maya怎么建模稻草人模型?

    一、概念1、稻草人的经典外观:巨大的帽子,旧裤子,衣服撕开,露出部分稻草,旧木棍,巨大的靴子和大眼睛,人的比例稍微夸张。2、第二步是乌鸦。乌鸦类似飞行中...

    2019-08-23 来源: 浏览:31 次

    分享
  • CodePush自定义更新弹框及下载进度条

    CodePush自定义更新弹框及下载进度条

    下载进度条组件progress 这里也是封装成一个组件,核心代码如下:.........

    2019-08-23 来源: 浏览:93 次

    分享
  • 穷举(四):POJ上的两道穷举例题P

    穷举(四):POJ上的两道穷举例题P

    下面给出两道poj上的问题,看如何用穷举法解决。calling extraterrestrial intelligence againdescrip.........

    2019-08-23 来源: 浏览:49 次

    分享
  • Android网络框架的优缺点、图片加载框

    Android网络框架的优缺点、图片加载框

    高并发网络连接;通过标准的 http cache coherence缓存磁盘和内存透明的响应;支持指定请求的优先级; 提供多样的取消机制:网络请求 cancel.........

    2019-08-23 来源: 浏览:26 次

    分享
  • Entity

    Entity

    开发环境:VS2017 数据库:SQL 2012本文是学习EF的第一篇笔记,参考lloydsheng的帖子实践,总结记录。先创建一个空白的解决方案,后续关于EF.........

    2019-08-21 来源: 浏览:31 次

    分享
  • 社交电商正当时,苏宁推客818新计划

    社交电商正当时,苏宁推客818新计划

    2019年对于电商行业来说,是不平凡的一年,社交电商异军突起,短时间内就成为电商界的一匹黑马。《中国社交电商行业发展报告》指出,预计到2020年,社交电商市场规.........

    2019-08-21 来源: 浏览:37 次

    分享
  • 报告:互联网

    报告:互联网

    在这种情况下,互联网/IT业对高校毕业生的吸引力不断增强,成为不少人的求职首选。数据显示:近五年大学毕业生从事互联网/IT行业类的比例总体上升,满意度、月收入...

    2019-08-21 来源: 浏览:60 次

    分享
  • IT企业实习岗位需求旺盛

    IT企业实习岗位需求旺盛

    该指南收集了2017年1月以来,44695个线上发布的在蓉实习岗位需求和142907名有意来蓉实习学生的相关数据,从企业类别、产业领域、学生专业、周期时长、收入.........

    2019-08-21 来源: 浏览:57 次

    分享
  • C语言中#ifdef,#ifndef和#endif的作用

    C语言中#ifdef,#ifndef和#endif的作用

    这些命令让编译器进行简单的逻辑控制. 当一个文件被编译时, 你可以使用这些命令使某些行保留或者是去处. #if expression如果表达式的值是 真 ,那么.........

    2019-08-19 来源: 浏览:23 次

    分享
  • Java连载16

    Java连载16

    因此我们在实际开发过程中如果没有特殊要求尽量使用++在前面二、关系运算符 大于 小于 =大于等于 =小于等于==等于!=不等于注意:关系运算符的运算结果一定是.........

    2019-08-19 来源: 浏览:83 次

    分享
  • Springboot 2使用SpringApplication

    Springboot 2使用SpringApplication

    使用静态方法springapplication.run;使用构造器springapplication app = new springapplication;a.........

    2019-08-19 来源: 浏览:9 次

    分享
  • gif图片转换为jpg格式 java

    gif图片转换为jpg格式 java

    可参照 https://blog.csdn.net/huoji555/article/details/79595137 if.endswith){//由于头像.........

    2019-08-19 来源: 浏览:18 次

    分享
换一换
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。