78.方块转换
题目描述
一块N x N(1=<N<=10)正方形的黑白瓦片的图案要被转换成新的正方形图案。
写一个程序来找出将原始图案按照以下列转换方法转换成新图案的最小方式:
#1:转90度:图案按顺时针转90度。
#2:转180度:图案按顺时针转180度。
#3:转270度:图案按顺时针转270度。
#4:反射:图案在水平方向翻转(形成原图案的镜像)。
#5:组合:图案在水平方向翻转,然后按照#1-#3之一转换。
#6:不改变:原图案不改变。
#7:无效转换:无法用以上方法得到新图案。
如果有多种可用的转换方法,请选择序号最小的那个。
比如:
转换前:
@-@
@@-
转换后:
@-@
@--
--@
这种转换采取#1(按顺时针转90度)即可。
注意:图案中的字符"@"和"-"在转90度后,还是"@"和"-"。不要认为"-"转90度后变成"|"。
代码
cpp
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 定义图案类型
typedef vector<string> Pattern;
int N;
// 检查两个图案是否完全相同
bool isEqual(const Pattern& a, const Pattern& b) {
for (int i = 0; i < N; ++i) {
if (a[i] != b[i]) return false;
}
return true;
}
// 顺时针旋转 90 度
Pattern rotate(const Pattern& p) {
Pattern newP(N, string(N, ' '));
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
newP[j][N - 1 - i] = p[i][j];
}
}
return newP;
}
// 水平翻转
Pattern reflect(const Pattern& p) {
Pattern newP(N, string(N, ' '));
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
newP[i][N - 1 - j] = p[i][j];
}
}
return newP;
}
int main() {
if (cin >> N) {
Pattern start(N), end(N);
// 读取转换前的图案
for (int i = 0; i < N; ++i) cin >> start[i];
// 读取转换后的图案
for (int i = 0; i < N; ++i) cin >> end[i];
// 按照题目要求的顺序依次检查
// 1: 转 90 度
Pattern r90 = rotate(start);
if (isEqual(r90, end)) {
cout << 1 << endl;
return 0;
}
// 2: 转 180 度 (即在 90 度的基础上再转 90 度)
Pattern r180 = rotate(r90);
if (isEqual(r180, end)) {
cout << 2 << endl;
return 0;
}
// 3: 转 270 度 (即在 180 度的基础上再转 90 度)
Pattern r270 = rotate(r180);
if (isEqual(r270, end)) {
cout << 3 << endl;
return 0;
}
// 4: 反射 (水平翻转)
Pattern ref = reflect(start);
if (isEqual(ref, end)) {
cout << 4 << endl;
return 0;
}
// 5: 组合 (反射后,再转 90, 180, 或 270)
Pattern ref90 = rotate(ref);
Pattern ref180 = rotate(ref90);
Pattern ref270 = rotate(ref180);
// 只要匹配其中任何一个角度,都算作5
if (isEqual(ref90, end) || isEqual(ref180, end) || isEqual(ref270, end)) {
cout << 5 << endl;
return 0;
}
// 6: 不改变
if (isEqual(start, end)) {
cout << 6 << endl;
return 0;
}
// 7: 无效转换
cout << 7 << endl;
}
return 0;
}
总结
变换函数:本题目需要两个核心函数:(所有操作都是基于这两个函数的组合)
rotate(): 将矩阵顺时针旋转 90 度。reflect(): 将矩阵水平翻转。
判断逻辑:严格按照题目要求的顺序(1 到 6)进行检查。一旦匹配成功,立即输出对应的编号并结束程序。如果 1-6 都不匹配,则输出 7。
80.饲料调配
农夫约翰从来只用调配得最好的饲料来为他的奶牛。
饲料用三种原料调配成:大麦,燕麦和小麦。他知道自己的饲料精确的配比,在市场上是买不到这样的饲料的。他只好购买其他三种混合饲料(同样都由三种麦子组成),然后将它们混合,来调配他的完美饲料。
给出三组整数,表示 大麦:燕麦:小麦 的比例,找出用这三种饲料调配 x:y:z 的饲料的方法。
例如,给出目标饲料 3:4:5 和三种饲料的比例:
1:2:3
3:7:1
2:1:2
你必须编程找出使这三种饲料用量最少的方案,要是不能用这三种饲料调配目标饲料,输出'NONE'。'用量最少'意味着三种饲料的用量(整数)的和必须最小。
对于上面的例子,你可以用8份饲料1,2份饲料2,和5份饲料3,来得到7份目标饲料: 8*(1:2:3) + 1*(3:7:1) + 5*(2:1:2) = (21:28:35) = 7*(3:4:5)
以上数字中,表示饲料比例的整数都是小于100(数量级)的非负整数,表示各种饲料的份数的整数都小于100。一种混合物的比例不会由其他混合物的比例直接相加得到。
代码
cpp
#include <iostream>
using namespace std;
int main() {
int target[3]; // 目标饲料比例
for (int i = 0; i < 3; ++i) cin >> target[i];
int feeds[3][3]; // 三种原料饲料的比例
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
cin >> feeds[i][j];
}
}
int min_sum = 999999;
int best_i = -1, best_j = -1, best_k = -1, best_m = -1;
// 暴力枚举 i, j, k
for (int i = 0; i < 100; ++i) {
for (int j = 0; j < 100; ++j) {
// 如果当前 i+j 已经超过已知的最优 min_sum,就没必要继续循环 k 了
if (i + j >= min_sum) break;
for (int k = 0; k < 100; ++k) {
// 排除全为0的情况(如果需要至少有一份饲料)
if (i == 0 && j == 0 && k == 0) continue;
if (i + j + k >= min_sum) break;
// 计算当前混合后的各成分总量
int mix_x = i * feeds[0][0] + j * feeds[1][0] + k * feeds[2][0];
int mix_y = i * feeds[0][1] + j * feeds[1][1] + k * feeds[2][1];
int mix_z = i * feeds[0][2] + j * feeds[1][2] + k * feeds[2][2];
//检查是否与目标比例匹配
int m = 0;
bool possible = true;
// 检查第一种成分 (X)
if (target[0] > 0) {
if (mix_x % target[0] != 0) possible = false;
else m = mix_x / target[0];
} else if (mix_x != 0) {
possible = false; // 目标是0但混合结果不是0,不匹配
}
// 检查第二种成分 (Y)
if (possible) {
if (target[1] > 0) {
if (mix_y % target[1] != 0) possible = false;
else {
int current_m = mix_y / target[1];
if (m == 0 && target[0] == 0) m = current_m; // 如果之前没确定 m
else if (m != current_m) possible = false; // m 必须一致
}
} else if (mix_y != 0) {
possible = false;
}
}
// 检查第三种成分 (Z)
if (possible) {
if (target[2] > 0) {
if (mix_z % target[2] != 0) possible = false;
else {
int current_m = mix_z / target[2];
if (m == 0 && target[0] == 0 && target[1] == 0) m = current_m;
else if (m != current_m) possible = false;
}
} else if (mix_z != 0) {
possible = false;
}
}
// 如果匹配且倍数 m > 0
if (possible && m > 0) {
int current_sum = i + j + k;
if (current_sum < min_sum) {
min_sum = current_sum;
best_i = i;
best_j = j;
best_k = k;
best_m = m;
}
}
}
}
}
// 输出结果
if (best_i != -1) {
cout << best_i << " " << best_j << " " << best_k << " " << best_m << endl;
} else {
cout << "NONE" << endl;
}
return 0;
}
总结
题目分析
-
目标:找到三个整数 i,j,ki, j, ki,j,k(分别代表三种饲料的份数),使得混合后的饲料比例与目标饲料比例一致。
-
约束条件:
- i,j,ki, j, ki,j,k 都是小于 100 的非负整数。
- 要求 i+j+ki + j + ki+j+k 的和最小。
- 混合后的总量必须是目标比例的整数倍。
-
方程:
设三种饲料的配比分别为 (a1,b1,c1)(a_1, b_1, c_1)(a1,b1,c1)、(a2,b2,c2)(a_2, b_2, c_2)(a2,b2,c2)、(a3,b3,c3)(a_3, b_3, c_3)(a3,b3,c3)。
需要满足:
i⋅a1+j⋅a2+k⋅a3=m⋅xti⋅b1+j⋅b2+k⋅b3=m⋅yti⋅c1+j⋅c2+k⋅c3=m⋅zt\begin{aligned} i \cdot a_1 + j \cdot a_2 + k \cdot a_3 &= m \cdot x_t \\ i \cdot b_1 + j \cdot b_2 + k \cdot b_3 &= m \cdot y_t \\ i \cdot c_1 + j \cdot c_2 + k \cdot c_3 &= m \cdot z_t \end{aligned}i⋅a1+j⋅a2+k⋅a3i⋅b1+j⋅b2+k⋅b3i⋅c1+j⋅c2+k⋅c3=m⋅xt=m⋅yt=m⋅zt
其中 mmm 必须是正整数。
算法思路
- 输入读取:读取目标比例和三种饲料的比例。
- 三重循环:使用三层循环分别枚举 i,j,ki, j, ki,j,k 从 0 到 99。
- 计算混合结果:在每一层循环中,计算当前组合下的混合饲料总量 。
81.求小数位数个数
题目描述
明明最近在一家软件公司实习,公司分配给他一个任务,要他写一个小程序,这个程序的功能是求出一个浮点数的小数部分的长度。例如程序输入1.1,则输出1,程序输入1.11,则输出2,明明觉得这个非常简单,花了不到5分钟的时间就把程序给写出来了,然后就把程序交给了测试员测试。但是没有想到的是,经过测试员的测试,发现了一大堆的错误,返回的结果很多都是不对的,这个令明明相当的不解,始终想不通自己的程序错在哪里。你是一名经验丰富的程序员,明明把这个问题来求助于你,明明和你说了他的想法,你一听就明白明明错在了哪里,原来明明使用double型来存放浮点数,但是由于double型的精度问题,不可能把所有的小数都精确的保存好,如果小数位数很长,就会出错。你发现了问题。现在请你写出正确的程序。 明明的问题可以归结为:给你一个浮点数,请你求出这个浮点数的小数位数。
代码
cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string n;
while (cin >> n) {
// 在字符串 n 中查找小数点 '.' 的位置
size_t pos = n.find('.');
if (pos == string::npos) {
// 如果没找到小数点,说明是整数,小数位数为 0
cout << 0 << endl;
} else {
// 如果找到了,小数部分的长度 = 总长度 - 小数点位置下标 - 1
cout << n.length() - pos - 1 << endl;
}
}
return 0;
}
总结
把输入看作一串普通的字符:
- 在字符串里找到小数点
.的位置。 - 数一下小数点后面还有多少个字符。
翻译
表 12C-2 总结了三个主要民用应用领域的物联网应用。显然,物联网有许多军事应用,但这超出了本节的范围。总的来说,使用物联网旨在促进工业生产力并提高经济增长。
物联网在环境保护方面发挥着重要作用,包括污染控制、天气预报以及灾害避免和恢复。在社会影响方面,物联网可以使我们的生活更加便捷和舒适。政府服务、执法以及家庭和健康改善是主要的受益者。
RFID 应用的出现强烈依赖于零售商 、物流组织和包裹递送公司的采用。特别是,零售商可以对单个物体进行标记,以便一次解决多个问题:精确的库存盘点、损失控制,以及支持无人值守 直通式销售终端的能力(这有望加快结账 速度,同时减少商店行窃和劳动力成本)。
civilian application domains 民用应用领域
beneficiaries ------ 受益者 / 受惠人
Emergence------ 出现 / 兴起
logistics ------ 物流 / 后勤
inventorying ------ 盘点 / 存货管理
unattended------ 无人值守的 / 无人照管的
