初学acmer--读《算法竞赛入门经典》笔记<四>(p36-41)

来源:互联网 发布:文献法包括网络 编辑:程序博客网 时间:2024/04/29 19:51

1.下面的程序运行结果是什么?(p36

#include<stdio.h>int main() {double i;for(i=9.9;i!=10;i+=0.1){printf("%.lf\n",i);}return 0;}
根据自己主观感觉,以为结果是9.9

运行发现是

10
10
10
10
10
10
10
11
11
11
11
11
11
11
11
11
11
12
12
12
。。。。

无限循环下去了

再仔细思索 发现两个问题

①double类型的数值进行运算得不到“数学上精确”的结果(详见点击打开链接)

②按%.lf输出,结果是忽略小数点后面的部分的

而按%x.ylf输出的话,结果是总共占x位,保留y位小数

接着稍稍改了代码,将for语句中的初始化语句改成i=10,运行结果不再无限循环了,也没输出



2.开灯问题(p39)

题目:有n盏灯,编号为1~n。第一个人把所有灯打开,第二个人按下所有编号为2的倍数的开关(这些灯将被关掉),第三个按下所有编号为3的倍数的开关(其中关掉的灯将被打开,开着的灯将被关掉)。以此类推,一共有k个人,问最后有哪些灯开着?输入n和k,输出开着的灯的编号。k<=n<=1000
样例输入:
7 3
样例输出:
1 5 6 7


分析:此题有一个特点:若数量较少时,人可以不借助任何外物就可以解决,但一旦数量过大,单凭人力就有些吃力了,所以就可以借助计算机超凡的计算力来“模拟”问题情境,从而解决问题。用a[1],a[2],a[3],... ,a[n]表示编号为1,2,3,...,n的灯是否开着,开闭状态可以用0和1表示。开关动作可以用取反来模拟(!0=1,!1=0)

代码如下:

#include<stdio.h>#include<string.h>               //下面的memset函数所需的头文件#define maxn 1010int a[maxn];int main(){int n,k,first=1;memset(a,0,sizeof(a));     //将数组a中的元素初始化为0scanf("%d%d",&n,&k);for(int i=1;i<=k;i++)  for(int j=1;j<=n;j++)    if(j%i==0)  a[j]=!a[j];   for(int i=1;i<=n;i++)   if(a[i]) {   if(first)   first=0;                //输出时保持空格,即除了第一个数,其余所有的数输出之前都先输出一个空格   else   printf(" ");   printf("%d",i);   }   printf("\n");   return 0;}

3.蛇形填数(P39)

题目:在n*n方阵里填入1,2,。。。,n*n,要求填成蛇形。例如,n=4时方阵为:

10 11 12 1

 9 16 13 2

 8 15 14 3

 7  6    5  4(方阵中,多余的空格不必严格输出。n<=8)

分析:同上一题特点一样,此题可以通过“模拟”来解。仔细分析,“笔”的移动轨迹为:下,下,下,左,左,左,上,上,上,右,右,下,下,左,上

容易发现都是四个过程一个循环(先下,再左,再上,最后右)。而且每次转向无非两种情况:一是再走就出界(如从4到5),二是再走就要走到以前走的格子(如从12到13)

第一种情况可以轻易判断,而第二种情况可以通过先将二维数组全部初始化为0,通过数组中元素是否为零判断是否已经填过


代码如下:

#include<stdio.h>#include<string.h>#define maxn 20int a[maxn][maxn];int main(){int n,x,y,tot=0;scanf("%d",&n);memset(a,0,sizeof(a));x=0;y=n-1;a[x][y]=1;tot=1;while(tot<n*n){while(x+1<n&&!a[x+1][y])  a[++x][y]=++tot;while(y-1>=0&&!a[x][y-1])  a[x][--y]=++tot;while(x-1>=0&&!a[x-1][y])   a[--x][y]=++tot;while(y+1<n&&!a[x][y+1])   a[x][++y]=++tot;}for(int i=0;i<n;i++) {  for(int j=0;j<n;j++)  printf("%3d",a[i][j]);  printf("\n"); } return 0;}
ps:四条while语句都遵循一个原则,就是先判断,后赋值,而不是赋完值再判断,因为若是出错,很难修改回来

提示:很多情况下,最好是在做一件事之前检查是不是可以做,而不要做完再后悔,因为“悔棋”往往比较麻烦





阅读全文
0 0
原创粉丝点击