Skip to content

Commit 7534c21

Browse files
committed
add niuke daily code tk2
1 parent 4abb473 commit 7534c21

5 files changed

Lines changed: 285 additions & 5 deletions

File tree

.vs/VSWorkspaceState.json

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
{
22
"ExpandedNodes": [
33
"",
4-
"\\leetcode",
5-
"\\leetcode\\Study Plan",
6-
"\\leetcode\\Study Plan\\3341_\u5230\u8FBE\u6700\u540E\u4E00\u4E2A\u623F\u95F4\u7684\u6700\u5C11\u65F6\u95F4_I",
7-
"\\leetcode\\Study Plan\\3350. \u68C0\u6D4B\u76F8\u90BB\u9012\u589E\u5B50\u6570\u7EC4 II"
4+
"\\CodeForce\\UTPC Contest 10-15-25 Div. 2 (Beginner)\\A. Trilobyte",
5+
"\\leetcode\\Study Plan\\2011. \u6267\u884C\u64CD\u4F5C\u540E\u7684\u53D8\u91CF\u503C",
6+
"\\niuke",
7+
"\\niuke\\daily_problem\\25_10-20\u3042\u306A\u305F\u306E\u86D9\u304C\u5E30\u3063\u3066\u3044\u307E\u3059",
8+
"\\niuke\\practice",
9+
"\\niuke\\practice\\noob"
810
],
9-
"SelectedNode": "\\leetcode\\Study Plan\\3350. \u68C0\u6D4B\u76F8\u90BB\u9012\u589E\u5B50\u6570\u7EC4 II\\1.py",
11+
"SelectedNode": "\\niuke\\practice\\noob\\noob28.cpp",
1012
"PreviewInSolutionExplorer": false
1113
}

.vs/slnx.sqlite

0 Bytes
Binary file not shown.
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#include<bits/stdc++.h>
2+
using namespace std;
3+
4+
int n; // 铁盘数量
5+
vector<int> target_state; // 目标状态(实际未使用,因为目标就是 [1,2,3,...,n])
6+
int max_depth; // IDA* 当前迭代的最大深度限制
7+
8+
/**
9+
* 启发式函数:估计从当前状态到目标状态还需要的最少步数
10+
*
11+
* 原理:计算"断点"数量
12+
* - 断点:相邻两个铁盘的编号差不是 1(说明它们在目标状态中不相邻)
13+
* - 每次翻转最多能消除 2 个断点
14+
* - 因此:所需步数 ≥ ceil(断点数 / 2)
15+
*
16+
* 例如:[3, 1, 2, 4]
17+
* - 3 和 1 之间:|3-1|=2 ≠ 1 → 断点
18+
* - 1 和 2 之间:|1-2|=1 = 1 → 不是断点
19+
* - 2 和 4 之间:|2-4|=2 ≠ 1 → 断点
20+
* - 4 不在最后位置(应该在最后) → 断点
21+
* 总共 3 个断点,估计至少需要 ceil(3/2) = 2 步
22+
*/
23+
int heuristic(const vector<int>& state) {
24+
int breakpoints = 0;
25+
26+
// 检查最大值(编号 n)是否在最底部(数组末尾)
27+
// 如果不在,说明最大值还需要移动,算一个断点
28+
if (state.back() != n) {
29+
breakpoints++;
30+
}
31+
32+
// 遍历相邻元素,检查它们的编号是否连续
33+
for (int i = 0; i < n - 1; ++i) {
34+
// 如果相邻元素编号差不是 1,说明它们在目标状态中不相邻
35+
// 需要通过翻转来调整,算作一个断点
36+
if (abs(state[i] - state[i + 1]) != 1) {
37+
breakpoints++;
38+
}
39+
}
40+
41+
return breakpoints;
42+
}
43+
44+
/**
45+
* 翻转函数:翻转数组的前 k 个元素
46+
*
47+
* @param arr 要翻转的数组(按值传递,不修改原数组)
48+
* @param k 翻转前 k 个元素
49+
* @return 翻转后的新数组
50+
*
51+
* 例如:flip([3, 1, 2, 4], 3) → [2, 1, 3, 4]
52+
*/
53+
vector<int> flip(vector<int> arr, int k) {
54+
reverse(arr.begin(), arr.begin() + k);
55+
return arr;
56+
}
57+
58+
/**
59+
* 深度优先搜索(DFS)+ 剪枝
60+
*
61+
* IDA* 核心:在限定深度内搜索解
62+
* 剪枝条件:g + h(state) > max_depth,即"已用步数 + 估计剩余步数 > 深度限制"
63+
*
64+
* @param state 当前状态(铁盘排列)
65+
* @param g 从起点到当前状态已经走了多少步(实际代价)
66+
* @param prev_flip 上一次翻转的位置 k(避免重复翻转,如 翻k → 翻k → 回到原状态)
67+
* @return 是否在当前深度限制内找到解
68+
*/
69+
bool dfs(const vector<int>& state, int g, int prev_flip) {
70+
// 计算启发式值:估计还需要多少步
71+
int h = heuristic(state);
72+
73+
// 剪枝:如果"已用步数 + 估计步数"超过深度限制,放弃这条路径
74+
// 这是 IDA* 的核心:用启发式函数来剪枝,避免搜索过深
75+
if (g + h > max_depth) {
76+
return false;
77+
}
78+
79+
// 目标检测:如果启发式值为 0,说明已经达到目标状态 [1,2,3,...,n]
80+
// (没有断点 = 所有相邻元素都连续 = 已排序)
81+
if (h == 0) {
82+
return true; // 找到解!
83+
}
84+
85+
// 尝试所有可能的翻转操作
86+
// k=2: 翻转前 2 个元素
87+
// k=3: 翻转前 3 个元素
88+
// ...
89+
// k=n: 翻转整个数组
90+
for (int k = 2; k <= n; ++k) {
91+
// 剪枝优化:避免连续两次翻转同一个位置
92+
// 因为 flip(k) → flip(k) 会抵消,回到原状态,是无效操作
93+
if (k == prev_flip) continue;
94+
95+
// 生成新状态:执行翻转操作
96+
vector<int> next_state = flip(state, k);
97+
98+
// 递归搜索:在新状态继续搜索
99+
// g+1: 步数加 1
100+
// k: 记录这次翻转的位置,下次避免重复翻转
101+
if (dfs(next_state, g + 1, k)) {
102+
return true; // 如果找到解,向上返回
103+
}
104+
}
105+
106+
// 所有可能都试过了,没找到解
107+
return false;
108+
}
109+
110+
int main() {
111+
ios::sync_with_stdio(false);
112+
cin.tie(NULL);
113+
114+
// 读取输入
115+
cin >> n;
116+
vector<int> start_state_raw(n); // 原始输入(实际半径值)
117+
vector<int> sorted_unique(n); // 用于排序和离散化
118+
119+
for (int i = 0; i < n; ++i) {
120+
cin >> start_state_raw[i];
121+
sorted_unique[i] = start_state_raw[i];
122+
}
123+
124+
// ========== 离散化处理 ==========
125+
// 为什么需要离散化?
126+
// 原始输入可能是:[87, 75, 19, 49, 46, ...](实际半径值)
127+
// 但我们只关心相对大小关系,不关心具体数值
128+
// 离散化后:将它们映射为 1, 2, 3, ..., n(排名)
129+
// 这样目标状态就是固定的 [1, 2, 3, ..., n],便于判断和启发
130+
131+
// 第一步:排序,得到从小到大的顺序
132+
sort(sorted_unique.begin(), sorted_unique.end());
133+
// 例如:[87, 75, 19, ...] → 排序后 → [1, 5, 11, 19, ...]
134+
135+
// 第二步:建立映射表(原始值 → 排名)
136+
map<int, int> val_to_rank;
137+
for (int i = 0; i < n; ++i) {
138+
val_to_rank[sorted_unique[i]] = i + 1;
139+
// 最小的值 → 排名 1
140+
// 次小的值 → 排名 2
141+
// ...
142+
// 最大的值 → 排名 n
143+
}
144+
145+
// 第三步:将原始状态转换为排名表示
146+
vector<int> start_state(n);
147+
for (int i = 0; i < n; ++i) {
148+
start_state[i] = val_to_rank[start_state_raw[i]];
149+
}
150+
// 例如:[87, 75, 19, ...] → [14, 13, 3, ...] (根据大小排名)
151+
152+
// ========== IDA* 迭代加深搜索 ==========
153+
// 什么是 IDA*?
154+
// - 结合了迭代加深(ID)和 A* 搜索
155+
// - 从深度 d=0 开始,如果找不到解,增加到 d=1, d=2, ...
156+
// - 每次深度限制内,用 DFS + 启发式剪枝搜索
157+
// - 优点:空间复杂度低(DFS),时间上有启发式加速
158+
159+
// 从启发式估计值开始迭代
160+
// 初始 max_depth = h(start_state):至少需要这么多步
161+
for (max_depth = heuristic(start_state); ; ++max_depth) {
162+
// 在深度限制 max_depth 内搜索
163+
// 参数:初始状态,已用步数 0,上一次翻转位置 0(表示没有)
164+
if (dfs(start_state, 0, 0)) {
165+
// 找到解!输出深度(即最少翻转次数)
166+
cout << max_depth << endl;
167+
break;
168+
}
169+
// 如果在当前深度找不到,增加深度继续搜索
170+
// max_depth++ 会在下一次循环执行
171+
}
172+
173+
return 0;
174+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
2+
//»¹Êdz¬Ê±
3+
#include <bits/stdc++.h>
4+
using namespace std;
5+
6+
typedef long long ll;
7+
8+
int minFlips(vector<int> arr) {
9+
int n = arr.size();
10+
11+
vector<int> target = arr;
12+
sort(target.begin(), target.end());
13+
14+
if (arr == target)return 0;
15+
16+
queue<pair<vector<int>, int>>q;
17+
map<vector<int>, bool>visited;
18+
19+
q.push({arr,0});
20+
visited[arr] = true;
21+
22+
while (!q.empty()) {
23+
auto [curr, steps] = q.front();
24+
q.pop();
25+
26+
for (int k = 2; k <= n; ++k) {
27+
vector<int> next = curr;
28+
reverse(next.begin(), next.begin() + k);
29+
30+
if (next == target)return steps + 1;
31+
32+
if (!visited[next]) {
33+
visited[next] = true;
34+
q.push({ next,steps + 1 });
35+
}
36+
}
37+
}
38+
39+
return -1;
40+
}
41+
42+
int main() {
43+
ios::sync_with_stdio(false), cin.tie(0);
44+
45+
int n;
46+
cin >> n;
47+
48+
vector<int> redius(n);
49+
50+
for (int i = 0; i < n; ++i)cin >> redius[i];
51+
52+
cout << minFlips(redius) << '\n';
53+
54+
55+
return 0;
56+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
#include <bits/stdc++.h>
3+
using namespace std;
4+
5+
typedef long long ll;
6+
7+
void flip(vector<int>& arr, int k) {
8+
reverse(arr.begin(), arr.begin() + k);
9+
}
10+
11+
int pancakeSort(vector<int>& arr) {
12+
int n = arr.size();
13+
int count = 0;
14+
15+
for (int currSize = n; currSize > 1; currSize--) {
16+
int maxidx = 0;
17+
for (int i = 1; i < currSize; ++i) {
18+
if (arr[i] > arr[maxidx])maxidx = i;
19+
}
20+
21+
if (maxidx == currSize - 1)continue;
22+
23+
if (maxidx > 0) {
24+
flip(arr, maxidx + 1);
25+
count++;
26+
}
27+
28+
flip(arr, currSize);
29+
count++;
30+
}
31+
32+
return count;
33+
34+
}
35+
36+
int main() {
37+
ios::sync_with_stdio(false), cin.tie(0);
38+
39+
int n;
40+
cin >> n;
41+
42+
vector<int> redius(n);
43+
for (int i = 0; i < n; i++)cin >> redius[i];
44+
45+
cout << pancakeSort(redius) << '\n';
46+
47+
return 0;
48+
}

0 commit comments

Comments
 (0)