ACM中的C题
题目描述
运行代码
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
if(n==1)
cout<<-1;
else if(n%2==0)
cout<<n/2;
else
cout<<n/2+1;
}
代码思路
一、总体思路
这段代码的目的是解决一个数组元素的交换问题,使得每个位置的元素与初始状态不同,同时要求输出最小交换次数。如果无法满足条件则输出 -1。
二、具体步骤原理
-
输入整数
n
:通过cin
从标准输入读取一个正整数n
,表示数组的长度。 -
判断特殊情况:如果
n
等于 1:当数组长度为 1 时,由于只有一个元素,无法进行交换使得元素与原来不同,所以输出 -1。 -
处理偶数长度数组:如果
n
是偶数:对于偶数长度的数组,可以通过两两交换相邻元素来满足每个位置的元素和原来都不相同的条件。例如,对于长度为 4 的数组[a, b, c, d]
,可以交换为[b, a, d, c]
。此时最小交换次数为n/2
,因为每两对相邻元素进行一次交换即可。 -
处理奇数长度数组:如果
n
是奇数:类似地,对于奇数长度的数组,可以先将前n - 1
个元素按照偶数长度数组的方法进行交换,然后最后一个元素与前面的某个元素交换位置。例如,对于长度为 5 的数组[a, b, c, d, e]
,先将前四个元素交换为[b, a, d, c]
,然后再将e
与a
(或b
、c
、d
中的任意一个)交换位置。所以最小交换次数为n/2 + 1
,其中n/2
是前n - 1
个元素的交换次数,再加上最后一个元素的一次交换。
ACM中的M题
题目描述
运行代码
#include <iostream>
#include <unordered_map>
using namespace std;
int main() {
int n;
cin >> n;
unordered_map<int, int> a;
for (int i = 0; i < n; ++i) {
int x;
cin >> x;
}
for (int i = 0; i < n; ++i) {
int y;
cin >> y;
a[y]++;
}
bool flag = false;
int ans = 0;
for (const auto& pair : a) {
if (pair.second == 1) {
flag = true;
break;
} else {
ans += (pair.second + 1) / 2;
}
}
if (flag) {
cout << -1 << endl;
} else {
cout << ans << endl;
}
return 0;
}
代码思路
一、总体思路
这段代码主要用于处理输入的一系列整数,统计每个整数的出现次数,然后根据统计结果进行特定的计算和输出。
二、具体步骤原理
-
读取整数
n
:从标准输入读取一个整数n
,代表后续输入的整数个数。 -
忽略第一轮输入:通过一个循环读取
n
个整数x
,但不对这些输入做任何处理。 -
统计第二轮输入的整数出现次数:再次通过一个循环读取
n
个整数y
。对于每个读取到的整数y
,将其作为键,在unordered_map a
中对应的值进行累加。这样就统计了每个整数在第二轮输入中出现的次数。 -
检查是否有整数只出现一次并计算结果:
- 遍历
unordered_map a
。 - 对于每个键值对
pair
,检查其值pair.second
(即对应整数的出现次数)。 - 如果出现次数为 1,则设置标志
flag
为true
,表示存在只出现一次的整数,跳出遍历。 - 如果出现次数不为 1,则计算
(pair.second + 1) / 2
并累加到ans
中。这里的计算可能是基于特定的问题需求,例如对于某个整数出现k
次,可能需要进行某种操作,而这个操作的代价可以通过(k + 1) / 2
来计算。
- 遍历
-
输出结果:
- 根据标志
flag
的值进行输出。 - 如果
flag
为true
,说明存在只出现一次的整数,按照要求输出 -1,表示无法满足特定条件。 - 如果
flag
为false
,则输出ans
,这个值是经过前面的计算得到的满足特定条件的结果。
- 根据标志
ACM中的AC题
题目描述
运行代码
#include <iostream>
#include <queue>
#include <vector>
#include <array>
#include <climits>
using namespace std;
typedef pair<int, int> PII;
const int N = 2010;
int n, m, sx, sy;
char g[N][N];
int dist[N][N];
int dist1[N][N];
const int dir1[][2] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
const int dir2[][2] = {{1, 0}, {-1, 0}, {0, -1}, {0, 1}};
void init() {
queue<PII> q;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (g[i][j] == '@') {
dist[i][j] = 0;
q.push({i, j});
}
}
}
while (!q.empty()) {
auto [x, y] = q.front();
q.pop();
for (int k = 0; k < 4; k++) {
int xx = x + dir1[k][0];
int yy = y + dir1[k][1];
if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && g[xx][yy]!= '#' && dist[xx][yy] == -1) {
dist[xx][yy] = dist[x][y] + 1;
q.push({xx, yy});
}
}
}
}
void solve() {
cin >> n >> m >> sx >> sy;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> g[i][j];
dist[i][j] = dist1[i][j] = -1;
}
}
init();
queue<array<int, 4>> q;
q.push({sx, sy, sx, sy});
dist1[sx][sy] = 0;
int ans = INT_MAX;
while (!q.empty()) {
auto [x, y, a, b] = q.front();
q.pop();
if (g[x][y] == '@' && dist[a][b] >= 0) {
ans = min(ans, dist1[x][y] + dist[a][b]);
}
if (g[a][b] == '@' && dist[x][y] >= 0) {
ans = min(ans, dist1[a][b] + dist[x][y]);
}
for (int k = 0; k < 4; k++) {
int xx = x + dir1[k][0];
int yy = y + dir1[k][1];
int aa = a + dir2[k][0];
int bb = b + dir2[k][1];
if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && g[xx][yy]!= '#' && dist1[xx][yy] == -1 && aa >= 1 && aa <= n && bb >= 1 && bb <= m && g[aa][bb]!= '#' && dist1[aa][bb] == -1) {
dist1[xx][yy] = dist1[x][y] + 1;
dist1[aa][bb] = dist1[a][b] + 1;
q.push({xx, yy, aa, bb});
}
}
}
if (ans == INT_MAX) {
ans = -1;
}
cout << ans << '\n';
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
solve();
return 0;
}
代码思路
一、总体思路
这段代码的目的是在一个给定的二维地图中,确定两个位于同一位置但只能反向移动的个体是否能够同时到达传送门,并计算出最短的移动序列长度,如果无法到达则输出 -1。
二、具体步骤原理
-
定义变量和常量:
N
:用于限定地图的最大尺寸。n
、m
:分别表示地图的行数和列数。sx
、sy
:起始位置的坐标。g[N][N]
:存储地图信息,字符代表不同的地块类型(平地、陷阱、传送门)。dist[N][N]
:用于存储从传送门到各个位置的最短距离。dist1[N][N]
:用于存储从起始位置出发,两个个体移动过程中的累积距离。dir1
和dir2
:分别表示两个个体移动的四个方向。
-
函数
init
:- 目的是初始化从传送门到各个位置的最短距离。
- 使用广度优先搜索(BFS)的方法,从地图中的传送门位置开始,向四个方向扩展,逐步计算到各个位置的最短距离,并将这些距离存储在
dist
数组中。如果某个位置是陷阱或者已经访问过,则不进行扩展。
-
函数
solve
:- 主处理函数。
- 首先读取地图的行数、列数和起始位置坐标,然后读取地图信息,并初始化
dist
和dist1
数组为 -1,表示未访问。 - 调用
init
函数初始化传送门到各个位置的最短距离。 - 使用一个队列存储两个个体的位置状态,队列中的元素是一个包含四个整数的数组,表示两个个体的坐标
{x,y,a,b}
。初始时将起始位置压入队列,并将dist1[sx][sy]
设为 0。 - 在循环中,每次从队列中取出一个状态,检查当前状态下两个个体的位置是否有一个到达传送门,并且另一个个体对应的传送门最短距离已知(非 -1)。如果满足条件,则计算当前状态下的总距离,并与已有的最小距离
ans
比较更新。 - 然后尝试四个方向的移动,检查新的位置是否合法(在地图内且不是陷阱且未访问过),如果合法则更新新位置的距离,并将新状态压入队列。
- 循环结束后,如果最小距离
ans
仍然是初始的极大值,则表示无法到达传送门,将其设为 -1 并输出;否则输出最小距离。
总之,这段代码通过 BFS 和状态扩展的方法,在二维地图中寻找两个只能反向移动的个体到达传送门的最短路径长度。其原理是利用了 BFS 能够找到最短路径的特性,以及对两个个体状态的同时处理来实现问题的求解。