目录
1.2n皇后问题
问题描述
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式
输入的第一行为一个整数n,表示棋盘的大小。
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
输出一个整数,表示总共有多少种放法。
样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
2
样例输入
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
0
示例代码
#include <iostream>
using namespace std;
int x[10];//第i行的白皇后放在第x[i]列上
int y[10];//第i行的黑皇后放在第y[i]列上
int c[10][10];
int n;//棋盘宽度以及皇后数量
int sum = 0;//计算解的数量
int abs(int n) {//求绝对值函数
if (n < 0) {
n = 0 - n;
}
return n;
}
//即将放入的白皇后坐标为(row,col),判断是否能够放置
int Place1(int row, int col) {
int flag = 0;
if (row == 1) {//对于第一行的棋子,由于没有前一行,只需要检测当前行是否可以放置棋子
if (c[row][col] == 0) {
flag = 1;
}
}
for (int i = 1; i < row; i++) //比较之前row -1行已经放置的白皇后
{
if (col == x[i] || abs(row - i) == abs(col - x[i]) || c[row][col] == 0) { //判断即将放的白皇后与已经存在的白皇后们是否处于同一列或同一斜线或者不能放置棋子
flag = 1;
break;
}
}
return flag;
}
//即将放入的黑皇后坐标为(row,col),判断是否能够放置
int Place2(int row, int col) {
int flag = 0;
if (row == 1) {//对于第一行的棋子,由于没有前一行,只需要检测当前行是否可以放置棋子
if (c[row][col] == 0) {
flag = 1;
}
}
for (int i = 1; i < row; i++) //比较之前row -1行已经放置的黑皇后
{
if (col == y[i] || abs(row - i) == abs(col - y[i]) || c[row][col] == 0) { //判断即将放的黑皇后与已经存在的黑皇后们是否处于同一列或同一斜线或者不能放置棋子
flag = 1;
break;
}
}
return flag;
}
//递归的回溯函数,若满足条件则往下递归,若不满足条件,则往前回溯
void Backtrack2(int t, int n) {
int temp = 1;
if (t == n + 1) {//n个黑皇后也放置好
sum++;
}
else {
//若这一行遍历到n仍不能放置黑皇后,则向前回溯
for (int i = 1; i <= n; i++) {
y[t] = i;
if (y[t] != x[t]) {//如果与同一行的白皇后位置不冲突
temp = 0;
}
else {
temp = 1;
}
if ((Place2(t, y[t]) + temp) == 0)//判断是否能放置黑皇后,只有两者都为0才行
Backtrack2(t + 1, n);//若这一行能放置黑皇后,则向下一行进行递归
}
}
}
//递归的回溯函数,若满足条件则往下递归,若不满足条件,则往前回溯,针对白皇后
void Backtrack1(int t, int n) {
int temp;
if (t == n + 1) {//白皇后放置完毕
Backtrack2(1, n);//开始放置黑皇后
}
else {
//若这一行遍历到n仍不能放置白皇后,则向前回溯
for (int i = 1; i <= n; i++) {
x[t] = i;
temp = Place1(t, x[t]);
if (temp == 0) {//判断是否能放置白皇后
Backtrack1(t + 1, n);//若这一行能放置白皇后,则向下一行进行递归
}
}
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) {//输入棋盘各个位置上的0 1
for (int j = 1; j <= n; j++) {
cin >> c[i][j];
}
}
Backtrack1(1, n);//从放置白皇后的第一行开始
cout << sum << endl;
return 0;
}
是n皇后的问题延伸,可以先调用Backtrack1函数找到n个白皇后,找到后就找黑皇后
2.报时助手
问题描述
给定当前的时间,请用英文的读法将它读出来。
时间用时h和分m表示,在英文的读法中,读一个时间的方法是:
如果m为0,则将时读出来,然后加上“o'clock”,如3:00读作“three o'clock”。
如果m不为0,则将时读出来,然后将分读出来,如5:30读作“five thirty”。
时和分的读法使用的是英文数字的读法,其中0~20读作:
0:zero, 1: one, 2:two, 3:three, 4:four, 5:five, 6:six, 7:seven, 8:eight, 9:nine, 10:ten, 11:eleven, 12:twelve, 13:thirteen, 14:fourteen, 15:fifteen, 16:sixteen, 17:seventeen, 18:eighteen, 19:nineteen, 20:twenty。
30读作thirty,40读作forty,50读作fifty。
对于大于20小于60的数字,首先读整十的数,然后再加上个位数。如31首先读30再加1的读法,读作“thirty one”。
按上面的规则21:54读作“twenty one fifty four”,9:07读作“nine seven”,0:15读作“zero fifteen”。
输入格式
输入包含两个非负整数h和m,表示时间的时和分。非零的数字前没有前导0。h小于24,m小于60。
输出格式
输出时间时刻的英文。
样例输入
0 15
样例输出
zero fifteen
示例代码
#include <iostream>
using namespace std;
string a[21] = { "zero","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty" };
string b[3] = { "thirty","forty","fifty" };
//a为0-20对应的英文字符串数组,b为30、40、50对应的英文字符串数组
int main()
{
int h, m, temp, size;//temp为中间变量,size为字符串的长度
cin >> h >> m;
if (h > 20) {//先对小时进行处理,如果大于20,则要用twenty + xxxxx来表示
size = a[20].length();//输出twenty
for (int i = 0; i < size; i++) {
cout << a[20][i];
}
cout << " ";
temp = h % 10;//输出减去20的部分
size = a[temp].length();
for (int i = 0; i < size; i++) {
cout << a[temp][i];
}
}
else {//如果小于等于20,就可以用0-20对应的英文字符串直接输出
size = a[h].length();
for (int i = 0; i < size; i++) {
cout << a[h][i];
}
}
cout << " ";
if (m == 0) {//如果分为0,则输出o'clock
cout << "o'clock";
}
else {//否则输出英文字符串
if (m > 20) {//如果大于20,则要用xxxxx + xxxxx来表示
temp = m / 10;//求得十位上的数
if (temp == 2) {//如果为2,输出twenty
size = a[20].length();
for (int i = 0; i < size; i++) {
cout << a[20][i];
}
}
else {//如果是3、4、5,则对应于数组b输出thirty、forty、fifty
size = b[temp - 3].length();
for (int i = 0; i < size; i++) {
cout << b[temp - 3][i];
}
}
cout << " ";
temp = m % 10;//输出个位上的数
size = a[temp].length();
for (int i = 0; i < size; i++) {
cout << a[temp][i];
}
}
else {//直接输出对应的英文字符串
size = a[m].length();
for (int i = 0; i < size; i++) {
cout << a[m][i];
}
}
}
return 0;
}
3.回形取数
问题描述
回形取数就是沿矩阵的边取数,若当前方向上无数可取或已经取过,则左转90度。一开始位于矩阵左上角,方向向下。
输入格式
输入第一行是两个不超过200的正整数m, n,表示矩阵的行和列。接下来m行每行n个整数,表示这个矩阵。
输出格式
输出只有一行,共mn个数,为输入矩阵回形取数得到的结果。数之间用一个空格分隔,行末不要有多余的空格。
样例输入
3 3
1 2 3
4 5 6
7 8 9
样例输出
1 4 7 8 9 6 3 2 5
样例输入
3 2
1 2
3 4
5 6
样例输出
1 3 5 6 4 2
示例代码
#include <iostream>
using namespace std;
int sum = 1, m, n;//sum=1是因为刚开始读取了最左上角的一个数
struct hui {
int finish = 0;//0表示未取过,1表示取过
int a = -1;//初始为-1,题目要求输入的是正整数,-1就相当于不可取
}b[202][202];
void kaishi(int direction, int row, int col) {
if (direction == 0) {//表示方向向下
row++;//由于此前对应的row,col已经读取过,方向向下,则 行+1
while (b[row][col].a != -1 && b[row][col].finish == 0) {//如果当前要读取的值不在边界并且未读取
cout << b[row][col].a << " ";
sum++;//记录读取过得数字数目
b[row][col].finish = 1;//将此位置置为完成读取状态
row++;//读取下一行
}
row--;//因为不能继续读取,则row--,消去while最后一次循环的row++
}
if (direction == 1) {//表示方向向右
col++;
while (b[row][col].a != -1 && b[row][col].finish == 0) {
cout << b[row][col].a << " ";
sum++;
b[row][col].finish = 1;
col++;
}
col--;
}
if (direction == 2) {//表示方向向上
row--;
while (b[row][col].a != -1 && b[row][col].finish == 0) {
cout << b[row][col].a << " ";
sum++;
b[row][col].finish = 1;
row--;
}
row++;
}
if (direction == 3) {//表示方向向左
col--;
while (b[row][col].a != -1 && b[row][col].finish == 0) {
cout << b[row][col].a << " ";
sum++;
b[row][col].finish = 1;
col--;
}
col++;
}
direction = (direction + 1) % 4;//方向左转,下->右->上->左->下..........
if (sum != (m * n)) {//如果还有数没有读取到,继续读取
kaishi(direction, row, col);
}
}
int main()
{
int direction = 0;//初始方向置为向下
cin >> m >> n;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
cin >> b[i][j].a;
}
}
cout << b[1][1].a << " ";//先读取第一个数字
b[1][1].finish = 1;//状态置为已经读取过
kaishi(direction, 1, 1);//开始读取接下来的数
return 0;
}
为了方便确定边界,因为可能读取的时候遇到-1行的情况,我加了一个边界包裹着这些要读取的数
4.龟兔赛跑预测
问题描述
话说这个世界上有各种各样的兔子和乌龟,但是研究发现,所有的兔子和乌龟都有一个共同的特点——喜欢赛跑。于是世界上各个角落都不断在发生着乌龟和兔子的比赛,小华对此很感兴趣,于是决定研究不同兔子和乌龟的赛跑。他发现,兔子虽然跑比乌龟快,但它们有众所周知的毛病——骄傲且懒惰,于是在与乌龟的比赛中,一旦任一秒结束后兔子发现自己领先t米或以上,它们就会停下来休息s秒。对于不同的兔子,t,s的数值是不同的,但是所有的乌龟却是一致——它们不到终点决不停止。
然而有些比赛相当漫长,全程观看会耗费大量时间,而小华发现只要在每场比赛开始后记录下兔子和乌龟的数据——兔子的速度v1(表示每秒兔子能跑v1米),乌龟的速度v2,以及兔子对应的t,s值,以及赛道的长度l——就能预测出比赛的结果。但是小华很懒,不想通过手工计算推测出比赛的结果,于是他找到了你——安徽大学计算机系的挂科生——请求帮助,请你写一个程序,对于输入的一场比赛的数据v1,v2,t,s,l,预测该场比赛的结果。
输入格式
输入只有一行,包含用空格隔开的五个正整数v1,v2,t,s,l,其中(v1,v2<=100;t<=300;s<=10;l<=10000且为v1,v2的公倍数)
输出格式
输出包含两行,第一行输出比赛结果——一个大写字母“T”或“R”或“D”,分别表示乌龟获胜,兔子获胜,或者两者同时到达终点。
第二行输出一个正整数,表示获胜者(或者双方同时)到达终点所耗费的时间(秒数)。
样例输入
10 5 5 2 20
样例输出
D
4
样例输入
10 5 5 1 20
样例输出
R
3
样例输入
10 5 5 3 20
样例输出
T
4
示例代码
#include <iostream>
using namespace std;
int main()
{
int v1, v2, t, s, l, t1 = 0, s1 = 0, s2 = 0, flag = 1;//s1为兔子跑的距离,s2为乌龟跑的距离,flag为0表示为乌龟在兔子休息时跑到了终点
cin >> v1 >> v2 >> t >> s >> l;
while (max(s1, s2) < l) {//当两个人都没到达终点
s1 = s1 + v1;//两个都跑,每秒记一次
s2 = s2 + v2;
t1++;
if (max(s1, s2) < l) {//双方都正常跑,但未到达终点
while ((s1 - s2) >= t) {//用while循环是因为,可能兔子等完一轮,乌龟还是和兔子相距较远
s2 = s2 + s * v2;
t1 += s;
if (s2 >= l) {//如果在兔子休息的过程中,乌龟跑到了终点
t1 -= (s2 - l) / v2;//去除多跑的时间
cout << "T" << endl << t1;//乌龟获胜
flag = 0;
break;
}
}
}
}
if (flag == 1)
{
if (s1 == max(s1, s2) && s2 == max(s1, s2)) {//龟兔同时到达了终点
cout << "D" << endl << t1;
}
else if (s1 == max(s1, s2)) {//兔子正常跑到终点
cout << "R" << endl << t1;
}
else if (s2 == max(s1, s2)) {//乌龟正常跑到终点
cout << "T" << endl << t1;
}
}
return 0;
}
5.芯片测试
问题描述
有n(2≤n≤20)块芯片,有好有坏,已知好芯片比坏芯片多。
每个芯片都能用来测试其他芯片。用好芯片测试其他芯片时,能正确给出被测试芯片是好还是坏。而用坏芯片测试其他芯片时,会随机给出好或是坏的测试结果(即此结果与被测试芯片实际的好坏无关)。
给出所有芯片的测试结果,问哪些芯片是好芯片。
输入格式
输入数据第一行为一个整数n,表示芯片个数。
第二行到第n+1行为n*n的一张表,每行n个数据。表中的每个数据为0或1,在这n行中的第i行第j列(1≤i, j≤n)的数据表示用第i块芯片测试第j块芯片时得到的测试结果,1表示好,0表示坏,i=j时一律为1(并不表示该芯片对本身的测试结果。芯片不能对本身进行测试)。
输出格式
按从小到大的顺序输出所有好芯片的编号
样例输入
3
1 0 1
0 1 0
1 0 1
样例输出
1 3
示例代码
#include <iostream>
#include<algorithm>
using namespace std;
int qiu(int b[10]) {//求b中有多少个1,即正确芯片
int size = 0;
for (int i = 1; i <= 10; i++)
{
if (b[i] == 1) {
size++;
}
}
return size;
}
int main()
{
int n, a[10][10], b[10], temp, count, count1, size, c[10];//数组b用来存储每个芯片的正确与否,c用来存储正确的芯片,size为b中争正确芯片数的大小
cin >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> a[i][j];
}
}
for (int i = 1; i <= n; i++) {//从第一个芯片开始遍历,假设它是正确的
for (int j = 1; j <= n; j++) {//通过假设第i个芯片正确得出的各个芯片结果
b[j] = a[i][j];
}
size = qiu(b);//求得正确芯片的数量
//cout << i<<"轮的正确芯片数" << size << endl;
count1 = 1;//因为假设刚开始的芯片也算正确的,所以为1
for (int j = 1; j <= n; j++) {//开始读取其他芯片
if (j != i && b[j] == 1) {//假设得出的好芯片且不包括第i个芯片
//cout <<i<<"轮的芯片" << j << endl;
count = 0;//当前芯片对其他芯片的判断情况与假设正确的芯片有多少个一样的判断
for (int k = 1; k <= n; k++) {
if (a[j][k] == b[k]) {//对应判断相同
count++;
}
else {//不相同,说明此芯片和预测芯片不一样,预测芯片为错的
break;
}
}
if (count == n) {//当前芯片与 假设芯片对其他芯片看法一样
count1++;
}
}
}
int temp2 = 1;
if (count1 == size) {//假设的芯片正确
for (int k = 1; k <= n; k++) {
if (b[k] == 1) {//正确芯片存入c中
c[temp2] = k;
temp2++;
}
}
sort(c + 1, c + size + 1);//从小到大排序
for (int k = 1; k <= size; k++) {
cout << c[k] << " ";
}
break;//已经找到正确芯片序列,结束!
}
}
return 0;
}