3-1 开灯问题
有n盏灯,编号为1~n。第一个人把所有打开,第2个人按下所有编号为2的倍数的开关(这些灯将被关掉),第3个人按下所有编号为3的倍数的开关 (其中关掉的灯被打开你,开着的灯将被关闭),一次类推。一共有k个人,问最后又哪些灯开着?输入 :n和k,输出开着的灯编号。k <= n <= 1000.
样例输入:7 3
样例输出:1 5 6 7
Code#include<stdio.h>
#include<string.h>
const int maxn = 1000 + 5;
int main()
{
int n, k, light[maxn], t = -1;
while(scanf("%d%d", &n, &k) == 2)
{
t = -1;
memset(light, -1, sizeof(light)); //初始状态都是关着的(1表示开,-1表示关)
for(int i = 1; i <= k; ++i)
for(int j = i; j <= n; j += i)
light[j] *= t;
for(int i = 1; i <= n; ++i)
if(light[i] == 1)
printf("%d ", i);
printf("\n");
}
return 0;
}
3-2 蛇形填数(抽象问题)
在n*n方阵里填入1,2,…,n*n,要求填成蛇形。例如4时方阵为:
10 11 12 1
9 16 13 2
8 15 14 3
7 6 5 4
上面的方阵中,多余的空格只是为了便于观察规律,不必严格输出。n <= 8。
从x=0,y=n-1,即第0行,第n-1列。“笔”的移动轨迹是:下,下,下,,左,左,左,上,上,上,右,右,下,下,上。总之,先是下,都不能填了为止,然后是左,接着是上,最后是右。“不能填”是指再走就出界了,或者再走就要走到以前体拿过的格子。如果我们把所有格子初始化为0,就能方百年地加以判断。
Code1#include<stdio.h>
#include<string.h>
const int maxn = 5000+10;
int snag[maxn][maxn];
int main()
{
int n, x, y;
while(scanf("%d", &n) == 1)
{
memset(snag, 0, sizeof(snag)); //设置标志以方便判断数组是否已经赋值
int num = snag[x=0][y=n-1]= 1;
while(num < n*n)
{
//抽象为下、左、上、右四个方向的移动,
while(x+1 < n && !snag[x+1][y]) snag[++x][y] = ++num;
while(y-1 >= 0 && !snag[x][y-1]) snag[x][--y] = ++num;
while(x-1 >= 0 && !snag[x-1][y]) snag[--x][y] = ++num;
while(y+1 < n && !snag[x][y+1]) snag[x][++y] = ++num;
}
for(x = 0; x < n; ++x)
{
for(y = 0; y < n; ++y)
printf("%3d ", snag[x][y]);
printf("\n");
}
}
return 0;
}
C++_Style:
Code2#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 5000 + 10;
int a[maxn][maxn];//(当数组很大时)数组必须开到外面
int main()
{
int n;
while(cin >> n)
{
int x, y, cnt;
memset(a, 0, sizeof(a));
cnt = a[x=0][y=n-1] = 1;
while(cnt < n*n)
{
while(x+1 < n && !a[x+1][y]) a[++x][y] = ++cnt;
while(y-1 >= 0 && !a[x][y-1]) a[x][--y] = ++cnt;
while(x-1 >= 0 && !a[x-1][y]) a[--x][y] = ++cnt;
while(y+1 < n && !a[x][y+1]) a[x][++y] = ++cnt;
}
for(x = 0; x < n; ++x)
{
for(y=0; y < n; ++y)
{
cout.width(5);
cout.setf(ios::right);
cout << a[x][y] << " ";
}
cout << endl;
}
}
return 0;
}
3-3 竖式问题
找出所有形如abc*de(三位数乘以两位数)的算式,使得在完整的竖式中,所有数字都属于一个特定的集合。输入数字集合(相邻数字之间没有空格),输出所有竖式。每个竖式前对应有编号,只有应有一个空行。最后输出解的总数。
样例输入:2357
样例输出:
<1>
775
X 33
-----
2325
2325
-----
25575
The number of solutions = 1
Code#include<stdio.h>
#include<string.h>
int main()
{
int i, ok, abc, de, x, y, z, count;
char s[20], buf[99];
//printf("%c\n", 999);?的ASCII码是999.
while(scanf("%s", s) == 1)
{
count = 0;
for(abc = 111; abc <= 999; abc++)
for(de = 11; de <= 99; de++)
{
x = abc*(de%10); //x存储与各位相乘的结果
y = abc*(de/10); //y存储与市十位相乘的结果
z = abc*de; //z存储最终结果
sprintf(buf, "%d%d%d%d%d", abc, de, x, y, z);
ok = 1;
for(i = 0; i < strlen(buf); i++)
if(strchr(s, buf[i]) == NULL)//如果在s中buf[i]不存在,ok置0
ok = 0;
if(ok)
{
printf("<%d>\n", ++count);
printf("%5d\nX%4d\n-----\n%5d\n%4d\n-----\n%5d\n\n", abc, de, x, y, z);
}
}
printf("The number of solutions = %d\n", count);
}
return 0;
}
3-4 回文串(编码阶段可以采用迭代式开发:每次只实现一点小功能,但要充分测试,确保它工作正常。)
输入一个字符串,求出其中最长的回文子串。字串的含义是:在原串中连续出现的字符串片段。回文的含义是:正着看和倒着看相同,如abba和yyxyy。在判断时,应该忽略suoyou8标点符号和空格,且忽略大小写,单输出应保持鸳鸯(在回文串的首部和尾部不要输出多余字符)。输入字符串长度不超过5000,且占据单独一行。应该输出最长的回文串,如果有多个,输出起始位置最靠左的。
样例输入:Cofuciuss say:Madam,i'm Adam.
样例输出:Madam, i'm Adam
Code#include<stdio.h>
#include<string.h>
#include<ctype.h>
const int maxn = 5000+10;
char buf[maxn], str[maxn];
int sub[maxn];
int main()
{
while(fgets(buf, maxn, stdin))
{
int len = strlen(buf), cnt = 0;
for(int i = 0; i < len; ++i)
if(isalpha(buf[i]))
{
sub[cnt] = i; //存入下标
str[cnt++] = toupper(buf[i]);
}
int max = 0, beg, end;
for(int i = 0; i < cnt; ++i)
{
for(int j = 0; i-j >= 0 && i+j < cnt; ++j)
{
//偶数个
if(str[i-j] != str[i+j]) break;
if(2*j+1 > max)
{
max = 2*j + 1;
beg = sub[i-j];
end = sub[i+j];
}
}
for(int j = 0; i-j >= 0 && i+j+1 < cnt; ++j)
{
//奇数个
if(str[i-j] != str[i+j+1]) break;
if(2*j+2 > max)
{
max = 2*j + 2;
beg = sub[i-j];
end = sub[i+j+1];
}
}
}
for(int i = beg; i <= end; ++i)
putchar(buf[i]);
putchar('\n');
}
return 0;
}
/*