This commit is contained in:
programmercarl
2024-08-01 10:25:20 +08:00
parent 06997eb9b9
commit d1be6070c2
7 changed files with 610 additions and 673 deletions

View File

@@ -158,16 +158,11 @@
节点5 -> 节点6权值为-2 minDist[6] > minDist[5] + (-2) ,更新 minDist[6] = minDist[5] + (-2) = 3 - 2 = 1
如图
如图将节点3加入队列因为节点6已经在队列里所以不用重复添加
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240412110509.png)
因为节点3 和 节点6 都曾经加入过队列,不用重复加入,避免重复计算。
在代码中我们可以用一个数组 visited 来记录入过队列的元素,加入过队列的元素,不再重复入队列。
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240729161116.png)
所以我们在加入队列的过程可以有一个优化用visited数组记录已经加入队列的元素已经在队列的元素不用重复加入
--------------
@@ -175,11 +170,12 @@
节点6作为终点没有可以出发的边。
同理从队列中取出节点3也没有可以出发的边
所以直接从队列中取出,如图:
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240411115424.png)
----------
这样我们就完成了基于队列优化的bellman_ford的算法模拟过程。
@@ -190,12 +186,12 @@
在上面模拟过程中,我们每次都要知道 一个节点作为出发点连接了哪些节点。
如果想方便知道这些数据,就需要使用邻接表来存储这个图,如果对于邻接表不了解的话,可以看 [kama0047.参会dijkstra堆](./kama0047.参会dijkstra堆.md) 中 图的存储 部分。
如果想方便知道这些数据,就需要使用邻接表来存储这个图,如果对于邻接表不了解的话,可以看 [kama0047.参会dijkstra堆](./0047.参会dijkstra堆.md) 中 图的存储 部分。
整体代码如下:
```CPP
```
#include <iostream>
#include <vector>
#include <queue>
@@ -215,7 +211,9 @@ int main() {
int n, m, p1, p2, val;
cin >> n >> m;
vector<list<Edge>> grid(n + 1); // 邻接表
vector<list<Edge>> grid(n + 1);
vector<bool> isInQueue(n + 1); // 加入优化,已经在队里里的元素不用重复添加
// 将所有边保存起来
for(int i = 0; i < m; i++){
@@ -230,24 +228,26 @@ int main() {
minDist[start] = 0;
queue<int> que;
que.push(start); // 队列里放入起点
que.push(start);
while (!que.empty()) {
int node = que.front(); que.pop();
isInQueue[node] = false; // 从队列里取出的时候,要取消标记
for (Edge edge : grid[node]) {
int from = node;
int to = edge.to;
int value = edge.val;
if (minDist[to] > minDist[from] + value) { // 开始松弛
minDist[to] = minDist[from] + value;
que.push(to);
minDist[to] = minDist[from] + value;
if (isInQueue[to] == false) { // 已经在队列里的元素不用重复添加
que.push(to);
isInQueue[to] = true;
}
}
}
}
if (minDist[end] == INT_MAX) cout << "unconnected" << endl; // 不能到达终点
else cout << minDist[end] << endl; // 到达终点最短路径
}

View File

@@ -1,11 +1,12 @@
# 三珠互斥
1. 如果k * 3 大于 n 了,那说明一定没结果,如果没想明白,大家举个例子试试看
2. 分别求出三个红珠子之间的距离
3. 对这三段距离从小到大排序 y1, y2, y3
4. 如果第一段距离y1 小于k说明需要交换 k - y 次, 同理 第二段距离y2 小于k说明需要交换 k - y2 次
5. y1 y2 都调整好了不用计算y3因为 y3是距离最大
```CPP
#include<bits/stdc++.h>
using namespace std;
@@ -29,12 +30,49 @@ int main(){
sort(dis.begin(), dis.end());
int result = 0;
if (dis[0] < k) result += (k - dis[0]);
if (dis[1] < k) result += (k - dis[1]);
cout << result << endl;
}
return 0;
}
```
Java代码
```Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
while (t-- > 0) {
int n = scanner.nextInt();
int k = scanner.nextInt();
int a1 = scanner.nextInt();
int a2 = scanner.nextInt();
int a3 = scanner.nextInt();
if (k * 3 > n) {
System.out.println(-1);
continue;
}
List<Integer> dis = new ArrayList<>(3);
dis.add(Math.min(Math.abs(a1 - a2), n - Math.abs(a1 - a2)));
dis.add(Math.min(Math.abs(a1 - a3), n - Math.abs(a1 - a3)));
dis.add(Math.min(Math.abs(a3 - a2), n - Math.abs(a3 - a2)));
Collections.sort(dis);
int result = 0;
if (dis.get(0) < k) result += (k - dis.get(0));
if (dis.get(1) < k) result += (k - dis.get(1));
System.out.println(result);
}
}
}
```

View File

@@ -1,4 +1,6 @@
# 扑克牌同花顺
首先我们要定义一个结构体,来存放我们的数据
`map<花色,{同一花色牌集合,同一花色的牌对应的牌数量}>`
@@ -51,3 +53,70 @@ int main() {
cout << sum << endl;
}
```
Java代码如下
```Java
import java.util.*;
public class Main {
static String[] cards = {"H", "S", "D", "C"}; // 花色数组
static class Color {
Set<Integer> st; // 同一花色牌的集合
Map<Integer, Long> cnt; // 同一花色牌对应的数量
Color() {
st = new HashSet<>(); // 初始化集合
cnt = new HashMap<>(); // 初始化映射
}
}
static Map<String, Color> umap = new HashMap<>(); // 用于存储每种花色对应的Color对象
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt(); // 读取牌的数量
for (int i = 0; i < n; i++) {
int x = scanner.nextInt(); // 读取牌的值
int y = scanner.nextInt(); // 读取牌的数量
String card = scanner.next(); // 读取牌的花色
umap.putIfAbsent(card, new Color()); // 如果不存在该花色则创建一个新的Color对象
umap.get(card).st.add(x); // 将牌的值加入集合
umap.get(card).cnt.put(x, umap.get(card).cnt.getOrDefault(x, 0L) + y); // 更新牌的数量
}
long sum = 0; // 结果累加器
// 遍历每一种花色
for (String cardOne : cards) {
Color colorOne = umap.getOrDefault(cardOne, new Color()); // 获取对应花色的Color对象
// 遍历同花色的每一张牌
for (int number : colorOne.st) {
long numberCount = colorOne.cnt.get(number); // 获取当前牌的数量
// 计算从当前牌到number+4的最小数量
long cal = numberCount;
for (int j = number + 1; j <= number + 4; j++) {
cal = Math.min(cal, colorOne.cnt.getOrDefault(j, 0L)); // 更新cal为最小值
}
// 将结果累加到sum
sum += cal;
// 将统计过的同花顺数量减去
for (int j = number + 1; j <= number + 4; j++) {
colorOne.cnt.put(j, colorOne.cnt.getOrDefault(j, 0L) - cal);
}
}
}
System.out.println(sum); // 输出结果
}
}
```

View File

@@ -1,6 +1,7 @@
# 149. 好数组
算是贪心
贪心思路:
整体思路是移动到中间位置(中位数),一定是 移动次数最小的。
@@ -11,9 +12,7 @@
代码如下:
```CPP
#include<bits/stdc++.h>
using namespace std;
int main() {
@@ -54,3 +53,50 @@ int main() {
return 0;
}
```
Java代码如下
```Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
long[] arr = new long[n];
for (int i = 0; i < n; ++i) {
arr[i] = scanner.nextLong();
}
Arrays.sort(arr);
if (arr[0] == arr[n - 1]) {
System.out.println(1);
return;
}
long cnt = 0L;
long cnt1 = 0L;
// 如果要保留一个不改变,要不不改最小的,要不不改最大的。
// 取中间偏前的位置
long mid = arr[(n - 2) / 2];
// 不改最大的
for (int i = 0; i < n - 1; i++) {
cnt += Math.abs(arr[i] - mid);
}
// 取中间偏后的位置
mid = arr[n / 2];
// 不改最小的
for (int i = 1; i < n; i++) {
cnt1 += Math.abs(arr[i] - mid);
}
System.out.println(Math.min(cnt, cnt1));
}
}
```

View File

@@ -1,21 +1,7 @@
# 150. 极长连续段的权值
按照动态规划的思路,每增加一位,对已有结果会有什么变化呢?
输入 字符串s 里面有 0 和 1
我们先计算出 s[i-1] 的 子串权值和 a
如果 s[i] 和 s[i - 1] 相同
下标0 到 i 这段字符串 的子串权值和就是 a + 1即算上s[i]本身的连续串数量加上
如果 s[i] 和 s[i - 1] 不相同
动态规划,枚举最后边节点的情况:
```CPP
#include <iostream>
@@ -32,9 +18,11 @@ int main() {
long long a = 1;
for (int i = 1; i < n; ++i) {
// 加上本身长度为1的子串
if (s[i] == s[i - 1]) {
a += 1;
result += a;
result += a;
// 以最右节点为终点,每个子串的级长连续段都+1再加本身长度为1的子串
} else {
a = a + i + 1;
result += a;
@@ -44,3 +32,35 @@ int main() {
return 0;
}
```
Java代码如下
```Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
String s = scanner.next();
long result = 1;
long a = 1;
for (int i = 1; i < n; ++i) {
// 加上本身长度为1的子串
if (s.charAt(i) == s.charAt(i - 1)) {
a += 1;
result += a;
// 以最右节点为终点,每个子串的级长连续段都+1再加本身长度为1的子串
} else {
a = a + i + 1;
result += a;
}
}
System.out.println(result);
}
}
```