目录
HDU1041——Computer Transformation
HDU1041——Computer Transformation
题目描述

题目翻译:
问题描述:最初,计算机中写入了一个由一位数字 1 组成的序列。在每个连续的时间步,计算机同时将每个数字 0 转换为序列 1 0,将每个数字 1 转换为序列 0 1。因此,在第一步之后,得到序列 0 1;在第二步之后,得到序列 1 0 0 1;在第三步之后,得到序列 0 1 1 0 1 0 0 1 等等。要找出经过 n 步后,序列中会出现多少对连续的 0 ?
输入:每一行输入包含一个自然数 n(0 < n ≤ 1000)。
输出:对于每个输入的 n,打印经过 n 步后序列中出现的连续 0 对的数量。
运行代码
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
// 这个函数实现的是两个字符串的加法操作。
string acm(string& co, string& gq) {
string str, strr;
int i, j;
int len_co = co.length();
int jin = 0, ji = 0, tmp, temp; // 进位标志,结果字符标志
// 字符串乘法实现,这里实际上是在进行二倍操作,即乘以2。
for (j = len_co - 1; j >= 0; j--) {
tmp = ((co[j] - '0') * 2 + jin) % 10;
jin = (co[j] - '0') * 2 / 10;
str = char(tmp + '0') + str;
}
if (jin) // 如果有进位,则添加到结果字符串最前面。
str = char(jin + '0') + str;
// 对齐两个字符串的长度,准备做加法。
int len_str = str.size();
int len_gq = gq.size();
int n = abs(len_str - len_gq);
if (len_str < len_gq)
for (i = 0; i < n; i++)
str = '0' + str;
else
for (i = 0; i < n; i++)
gq = '0' + gq;
// 字符串加法实现。
for (i = len_str - 1; i >= 0; i--) {
temp = str[i] - '0' + gq[i] - '0' + ji;
ji = temp / 10;
temp = temp % 10;
strr = char(temp + '0') + strr;
}
if (ji)
strr = char(ji + '0') + strr;
return strr;
}
// 主函数开始执行程序。
int main() {
int n;
string ls[1001]; // 存储每一步的结果序列。
// 初始化前两步的序列。
ls[1] = "0";
ls[2] = "1";
// 构建序列,这一步可以保留,但应该使用更有效的方法来计算连续0对。
for (int i = 3; i <= 1000; i++) {
ls[i] = acm(ls[i - 2], ls[i - 1]);
}
// 修改:读取用户输入并计算连续0对的数量。
while (cin >> n) {
const string& seq = ls[n];
int zeroPairs = 0; // 计算连续0对的数量。
// 遍历序列,计算连续0对的数量。
for (size_t i = 1; i < seq.size(); ++i) {
if (seq[i-1] == '0' && seq[i] == '0') {
zeroPairs++;
}
}
cout << zeroPairs << endl; // 输出连续0对的数量。
}
return 0;
}
代码思路
-
初始化: 我们从初始序列
"1"开始。 -
迭代更新序列:
- 在每一步中,我们将序列中的每一个
0替换成1 0,每一个1替换成0 1。 - 这意味着在第
n步后,序列的长度将是2^n。
- 在每一步中,我们将序列中的每一个
-
计算连续0对的数量:
- 在每一步结束时,我们遍历序列,如果遇到连续的
0,则增加计数器。 - 注意,由于序列的生成规则,连续的
0只可能出现在替换0为1 0后的位置上,因此我们只需要在每次替换后检查新生成的0是否与下一个字符构成一对连续的0。
- 在每一步结束时,我们遍历序列,如果遇到连续的
-
优化: 实际上,我们可以观察到连续0对的数量遵循一个模式,可以通过递推关系直接计算,而不需要实际生成序列。具体地,设
f(n)是第n步后连续0对的数量,那么f(n) = f(n-1) + f(n-2)。这是因为每次迭代,上一步的所有连续0对都将被保留,同时新的0对将在上上步的基础上产生(因为替换0会产生新的0,而这些新的0只可能与紧接着的0形成对)。初始条件是f(1) = 0和f(2) = 0。
HDU1042——N!
题目描述

运行代码
#include <iostream>
#include <cstring>
using namespace std;
int main() {
int n, i, j, end;
int a[100000] = { 0 };
while (cin >> n) {
memset(a, 0, sizeof(a));
end = 0;
a[0] = 1;
for (i = 1; i <= n; i++) {
// 模拟乘法运算,每一位都乘以 i
for (j = 0; j <= end; j++) {
a[j] = a[j] * i;
}
// 进位
for (j = 0; j <= end; j++) {
if (a[j] > 10000 && j == end) {
int c = a[j] / 10000;
a[j] = a[j] % 10000;
a[j + 1] += c;
end++;
}
else if (a[j] > 10000) {
int c = a[j] / 10000;
a[j] = a[j] % 10000;
a[j + 1] += c;
}
}
}
cout << a[end];
for (i = end - 1; i >= 0; i--) {
printf("%04d", a[i]);
}
cout << endl;
}
return 0;
}
代码思路
-
初始化:声明了一个足够大的数组
a,可以容纳最多100,000组四位数字。变量end用于追踪数组a中最后使用的索引。 -
输入循环:
- 程序从标准输入读取整数,直到没有更多的输入为止。
- 对于每次输入的
n,使用memset将数组a重置为全零。
-
阶乘计算:
- 一个循环从
1到n运行,模拟乘法操作,对这个范围内的每个数进行乘法运算。 - 在循环内部,数组
a的每一个元素都被乘以i。 - 乘法后,程序处理大于10,000的数值(因为每个
a[j]保存四位数字)的进位操作。如果某个值超过10,000,则除以10,000得到进位(c),余数则存回a[j]。进位加到数组中的下一个位置a[j+1]上,可能因此增加数字的长度,即end的值递增。
- 一个循环从
-
输出:程序以倒序方式打印计算出的阶乘,从最高有效位的四位数字开始。使用
%04d格式化字符串来打印每一组四位数字,确保任何不足四位的数字前有补零。
HDU1043——Eight
题目描述

运行代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N = 500005, has[9] = { 1,1,2,6,24,120,720,5040,40320 }, dx[4] = { -3,3,-1,1 };
int v1[N], v2[N];
char a[30], d1[10] = { "udlr" }, d2[10] = { "durl" };
string b = "123456780";
struct qw
{
int a;
char ch;
qw(int A = 0, char C = 0)
{
a = A, ch = C;
}
}pre[N];
struct qwe
{
int a;
string c;
qwe(int A = 0, string C = "")
{
a = A, c = C;
}
}e;
void print(int x)
{
if (pre[x].a == -1)
return;
print(pre[x].a);
printf("%c", pre[x].ch);
}
int ha(string e)
{
int s = 0, i, j, k;
for (i = 0; i < 9; i++)
{
k = 0;
for (j = 0; j < i; j++)
if (e[j] > e[i])
k++;
s += k * has[i];
}
return s;
}
int main()
{
while (gets_s(a))
{
int k = 0;
e.c = "";
for (int i = 0, j = 0; i < strlen(a); i++)
if (a[i] != ' ')
{
if (a[i] == 'x')
e.a = j, e.c += '0';
else
e.c += a[i];
j++;
}
for (int i = 0; i < 9; i++)
if (e.c[i] != '0')
for (int j = 0; j < i; j++)
if (e.c[j] != '0' && e.c[j] > e.c[i])
k++;
memset(v2, 0, sizeof(v2));
memset(v1, 0, sizeof(v1));
if (k & 1)
printf("unsolvable\n");
else
{
qwe f, g;
int a = 2;
queue<qwe>q1, q2;
v1[ha(e.c)] = 1;
pre[1].a = -1, pre[2].a = -1;
f = qwe(8, b);
v2[ha(f.c)] = 2;
q1.push(e), q2.push(f);
while (!q1.empty() && !q2.empty())
{
f = q1.front();
q1.pop();
int p = ha(f.c);
if (v2[p])
{
print(v1[p]);
for (int k = v2[p]; pre[k].a != -1; k = pre[k].a)
printf("%c", pre[k].ch);
printf("\n");
break;
}
for (int i = 0; i < 4; i++)
if ((i != 0 || f.a >= 3) && (i != 1 || f.a <= 5) && (i != 2 || f.a % 3 != 0) && (i != 3 || f.a % 3 != 2))
{
int x = f.a + dx[i];
g = f;
swap(g.c[f.a], g.c[x]);
int q = ha(g.c);
if (v1[q])
continue;
v1[q] = ++a;
g.a = x;
pre[a] = qw(v1[p], d1[i]);
q1.push(g);
}
f = q2.front();
q2.pop();
p = ha(f.c);
if (v1[p])
{
print(v1[p]);
for (int k = v2[p]; pre[k].a != -1; k = pre[k].a)
printf("%c", pre[k].ch);
printf("\n");
break;
}
for (int i = 0; i < 4; i++)
if ((i != 0 || f.a >= 3) && (i != 1 || f.a <= 5) && (i != 2 || f.a % 3 != 0) && (i != 3 || f.a % 3 != 2))
{
int x = f.a + dx[i];
g = f;
swap(g.c[f.a], g.c[x]);
int q = ha(g.c);
if (v2[q])
continue;
v2[q] = ++a;
g.a = x;
pre[a] = qw(v2[p], d2[i]);
q2.push(g);
}
}
}
}
return 0;
}
代码思路
-
数据结构和变量:
has[]:一个存储阶乘的数组,用于哈希函数中。dx[]:表示移动空白方块的方向(上、下、左、右)。d1[]和d2[]:分别表示第一个和第二个BFS队列的方向字符串。v1[]和v2[]:访问数组,用于跟踪第一次和第二次BFS队列中的状态。pre[]:一个数组,用于存储到达特定节点的父节点以及采取的方向。e,f和g:表示拼图状态及其相关属性的结构体。
-
哈希函数(
ha):这个函数根据每个方块的位置为给定的拼图状态计算一个哈希值。它使用的是逆序对的数量(相对于最终位置错乱的方块)乘以距离末尾位置的距离的阶乘。 -
主要逻辑:
- 读取输入字符串,得到拼图的初始配置。
- 判断拼图是否可解,通过计算初始状态下方块的逆序对数量。如果逆序对的数量是奇数,那么拼图无解。
- 使用两个队列进行双向BFS:一个从初始状态开始,向目标状态移动。另一个从目标状态开始,向初始状态移动。
- 对于两个队列中的每一个状态,它都会探索所有可能的移动,并更新访问状态和父节点信息。
- 如果在两个访问数组中找到相同的状态,就可以利用
print函数重构出解题路径。
-
路径重构(
print):通过遍历pre[]数组来打印导致解决方案的一系列移动。
142

被折叠的 条评论
为什么被折叠?



