当前位置: 首页 > news >正文

海岛奇兵声纳活动的数学解答

海岛奇兵声纳活动的数学解答

  • 概述
  • 游戏介绍
  • 源码
    • 基础环境
    • 基础计算逻辑
    • 可视化界面模块
  • 结语

概述

海岛声纳活动在之前的国际服上就已经上线了,但是那时候没太在意只觉得可以断网模拟也不错的。到国服上听说不能断网模拟,我就想到把他映射到数学问题上求解,似乎能更省炸弹。
不过大家可以看到b站上有很多断网模拟的教程,我试着玩了一会,一个一个试还是挺麻烦的。于是我最终还是决定写个程序吧,把这个算出来应该也比我一个一个盲试来的好。

目前该代码还是存在很多的问题,有时候点击方格切换成√状态会没有反应,我还没排查过原因(目前我的解决方法是先点击其他任意部位,趁代码还在计算更新时点回需要改变成√状态的格子)。其次该代码在有些情况下会失灵算出所有概率均为0,或许还有其他潜在的bug,代码仅供娱乐

游戏介绍

在海岛奇兵的声纳活动中,有着以下元素:一个正方形的探索区域,若干已知长度的潜艇埋藏在该区域中(只有横竖两种方向),以及探索区域的炸弹(分别有单格探索和指定单格+随机多格探索的炸弹,在这我们只讨论单格炸弹),游戏的通关目标便是找到探索区域内的所有潜艇。游戏中还有额外特性:

  • 潜艇未完全被发掘时只显示出其残骸状态,即无法辨别其方向
  • 潜艇在被完全发掘时,将展示其完整形态,并同时清空周围的所有格子(均为空)

源码

前提假设:潜艇出现在区域内的任何位置均是等可能的。
基于该游戏内容,我采用了古典概型计算所有格子存在潜艇的概率,同时使用贝叶斯公式将已知的探索结果视为条件计算未知结果的条件概率。不过以下代码在处理区域大小大于5×5时,由古典概型退化为采用蒙特卡洛估计(当区域过大以及潜艇数量种类增加时,传统方法的计算量会大大增加)。

基础环境

python版本并没有硬性要求

pip install numpy
pip install dash # 前端库

基础计算逻辑

import numpy as np
from collections import defaultdict
from functools import lru_cache# ================== 精确计算类 ==================
class BarProbabilityCalculator:def __init__(self, n, bar_dict, evidence_matrix):self.n = nself.bar_dict = bar_dictself.evidence_matrix = evidence_matrixself.total_bars = sum(bar_dict.values())self.known_covered = [(i,j) for i in range(n) for j in range(n) if evidence_matrix[i][j]==1]self.known_not_covered = [(i,j) for i in range(n) for j in range(n) if evidence_matrix[i][j]==-1]self.valid_placements = self._generate_valid_placements()self.placement_coverage = self._precompute_coverage()self.probability_matrix = Nonedef _generate_valid_placements(self):placements = []for m,count in self.bar_dict.items():for row in range(self.n):for start_col in range(self.n - m + 1):placement = ('H', m, row, start_col)if self._is_placement_valid(placement): placements.append(placement)for col in range(self.n):for start_row in range(self.n - m + 1):placement = ('V', m, col, start_row)if self._is_placement_valid(placement): placements.append(placement)return placementsdef _is_placement_valid(self, placement):type_, m, pos1, pos2 = placementif type_=='H':return not any((pos1,c) in self.known_not_covered for c in range(pos2,pos2+m))else:return not any((r,pos1) in self.known_not_covered for r in range(pos2,pos2+m))def _precompute_coverage(self):coverage = {}for placement in self.valid_placements:type_, m, pos1, pos2 = placementcells = set()if type_=='H':for c in range(pos2,pos2+m): cells.add((pos1,c))else:for r in range(pos2,pos2+m): cells.add((r,pos1))coverage[placement]=cellsreturn coveragedef _get_placement_cells(self, placement):return self.placement_coverage[placement]def _are_placements_compatible(self, placements):covered=set()for placement in placements:cells=self._get_placement_cells(placement)if cells & covered: return Falsecovered |= cellsreturn all(cell in covered for cell in self.known_covered)@lru_cache(maxsize=None)def _count_valid_combinations(self, bar_counts_tuple, used_placements_tuple=()):used_placements=list(used_placements_tuple)if all(c==0 for c in bar_counts_tuple):return 1 if self._are_placements_compatible(used_placements) else 0total=0bar_types=list(self.bar_dict.keys())bar_counts={bar_types[i]:bar_counts_tuple[i] for i in range(len(bar_types))}for m in bar_types:if bar_counts[m]>0:new_counts=bar_counts.copy(); new_counts[m]-=1new_counts_tuple=tuple(new_counts[bar_type] for bar_type in bar_types)for placement in self.valid_placements:if placement[1]==m and self._are_placements_compatible(used_placements+[placement]):total+=self._count_valid_combinations(new_counts_tuple, tuple(used_placements+[placement]))return totaldef compute_probability_matrix(self):if self.probability_matrix is not None: return self.probability_matrixprob_matrix=np.zeros((self.n,self.n))for i in range(self.n):for j in range(self.n):if self.evidence_matrix[i][j]==1: prob_matrix[i][j]=1.0elif self.evidence_matrix[i][j]==-1: prob_matrix[i][j]=0.0bar_types=list(self.bar_dict.keys())initial_counts=tuple(self.bar_dict[bt] for bt in bar_types)total_valid=self._count_valid_combinations(initial_counts)if total_valid==0:self.probability_matrix=prob_matrixreturn prob_matrixfor i in range(self.n):for j in range(self.n):if self.evidence_matrix[i][j]==0:cover_count=self._count_combinations_covering_cell(i,j,initial_counts)prob_matrix[i][j]=cover_count/total_validself.probability_matrix=prob_matrixreturn prob_matrixdef _count_combinations_covering_cell(self, ti,tj,bar_counts_tuple, used_placements_tuple=()):used_placements=list(used_placements_tuple)covered=any((ti,tj) in self._get_placement_cells(p) for p in used_placements)if all(c==0 for c in bar_counts_tuple):return 1 if self._are_placements_compatible(used_placements) and covered else 0total=0bar_types=list(self.bar_dict.keys())bar_counts={bar_types[i]:bar_counts_tuple[i] for i in range(len(bar_types))}for m in bar_types:if bar_counts[m]>0:new_counts=bar_counts.copy(); new_counts[m]-=1new_counts_tuple=tuple(new_counts[bt] for bt in bar_types)for placement in self.valid_placements:if placement[1]==m:cells=self._get_placement_cells(placement)new_placements=used_placements+[placement]if self._are_placements_compatible(new_placements):if covered or (ti,tj) in cells:total+=self._count_combinations_covering_cell(ti,tj,new_counts_tuple,tuple(new_placements))return total# ================== 蒙特卡洛类 ==================
class MonteCarloBarProbabilityCalculator:def __init__(self, n, bar_dict, evidence_matrix):self.n=n; self.bar_dict=bar_dict; self.evidence_matrix=evidence_matrixself.known_covered=[(i,j) for i in range(n) for j in range(n) if evidence_matrix[i][j]==1]self.known_not_covered=[(i,j) for i in range(n) for j in range(n) if evidence_matrix[i][j]==-1]self.valid_placements_by_type=self._generate_valid_placements_by_type()def _generate_valid_placements_by_type(self):placements=defaultdict(list)for m,count in self.bar_dict.items():for row in range(self.n):for start_col in range(self.n - m + 1):p=('H',m,row,start_col)if self._is_placement_valid(p): placements[m].append(p)for col in range(self.n):for start_row in range(self.n - m + 1):p=('V',m,col,start_row)if self._is_placement_valid(p): placements[m].append(p)return placementsdef _is_placement_valid(self,p):type_,m,pos1,pos2=pif type_=='H': return not any((pos1,c) in self.known_not_covered for c in range(pos2,pos2+m))else: return not any((r,pos1) in self.known_not_covered for r in range(pos2,pos2+m))def _get_placement_cells(self,p):type_,m,pos1,pos2=pcells=set()if type_=='H':for c in range(pos2,pos2+m): cells.add((pos1,c))else:for r in range(pos2,pos2+m): cells.add((r,pos1))return cellsdef compute_probability_matrix(self,num_samples=20000):prob_matrix=np.zeros((self.n,self.n))for i in range(self.n):for j in range(self.n):if self.evidence_matrix[i][j]==1: prob_matrix[i][j]=1.0elif self.evidence_matrix[i][j]==-1: prob_matrix[i][j]=0.0cover_counts=np.zeros((self.n,self.n)); valid_samples=0for _ in range(num_samples):placements=[]; covered=set(); valid=Truefor m,count in self.bar_dict.items():if not self.valid_placements_by_type[m]: valid=False; breaksize=min(count,len(self.valid_placements_by_type[m]))selected=np.random.choice(len(self.valid_placements_by_type[m]),size=size,replace=False)for idx in selected:placement=self.valid_placements_by_type[m][idx]cells=self._get_placement_cells(placement)if cells & covered: valid=False; breakcovered |= cells; placements.append(placement)if not valid: breakif not valid: continueif all(c in covered for c in self.known_covered):valid_samples+=1for i in range(self.n):for j in range(self.n):if (i,j) in covered and self.evidence_matrix[i][j]==0: cover_counts[i][j]+=1if valid_samples>0:prob_matrix+=cover_counts/valid_samplesreturn prob_matrix# ================== 入口函数 ==================
def compute_full_probability_matrix(n, bar_dict, evidence_matrix, method='auto'):total_bars=sum(bar_dict.values())if method=='auto':if n<=5 and total_bars<=3:method='exact'else:method='montecarlo'if method=='exact':calc=BarProbabilityCalculator(n,bar_dict,evidence_matrix)return calc.compute_probability_matrix()else:calc=MonteCarloBarProbabilityCalculator(n,bar_dict,evidence_matrix)return calc.compute_probability_matrix(num_samples=20000)# ================== 测试 ==================
if __name__=="__main__":n=6bar_dict={2:2,3:1}evidence_matrix=[[0]*n for _ in range(n)]prob_matrix=compute_full_probability_matrix(n,bar_dict,evidence_matrix)print("概率矩阵:")for row in prob_matrix:print(" ".join(f"{v:.2f}" for v in row))

可视化界面模块

import numpy as np
import dash
from dash import dcc, html, Input, Output, State, callback_context, ALL
import plotly.graph_objects as gofrom base_compute import compute_full_probability_matrix# ====== 颜色 ======
COLORS = {'background': '#282C34','text': '#E0E0E0','primary': '#61AFEF','secondary': '#C678DD','success': '#98C379','danger': '#E06C75','warning': '#E5C07B','section_bg': '#3A3F4B','bar_item_bg': '#4A505C',
}app = dash.Dash(__name__)# ====== 客户端回调 ======
app.clientside_callback("""function(barIds, removeClicks, addClicks, configDisplayId, barLibraryId, barStoreData) {const COLORS = {'background': '#282C34','text': '#E0E0E0','primary': '#61AFEF','secondary': '#C678DD','success': '#98C379','danger': '#E06C75','warning': '#E5C07B','section_bg': '#3A3F4B','bar_item_bg': '#4A505C',};const draggableBars = document.querySelectorAll('.draggable-bar');const dropTarget = document.getElementById('bar-config-display');draggableBars.forEach(bar => {if (!bar.dataset.dragListenerAdded) {bar.addEventListener('dragstart', (e) => {const length = JSON.parse(bar.id).length;e.dataTransfer.setData('text/plain', length);e.dataTransfer.effectAllowed = 'copy';bar.style.opacity = '0.4';});bar.addEventListener('dragend', (e) => { bar.style.opacity = '1'; });bar.dataset.dragListenerAdded = 'true';}});if (dropTarget && !dropTarget.dataset.dropListenerAdded) {dropTarget.addEventListener('dragover', (e) => {e.preventDefault();e.dataTransfer.dropEffect = 'copy';dropTarget.style.border = `2px dashed ${COLORS['warning']}`;});dropTarget.addEventListener('dragleave', (e) => {dropTarget.style.border = `1px dashed ${COLORS['text']}`;});dropTarget.addEventListener('drop', (e) => {e.preventDefault();dropTarget.style.border = `1px dashed ${COLORS['text']}`;const length = e.dataTransfer.getData('text/plain');if (length) {window.dash_clientside.set_props('drag-drop-store', {'data': {'last_dropped_length': parseInt(length), 'timestamp': Date.now()}});}});dropTarget.dataset.dropListenerAdded = 'true';}return window.dash_clientside.no_update;}""",Output('dummy-output', 'children'),Input({"type": "bar-draggable", "length": ALL}, "id"),Input({"type": "bar-remove-button", "length": ALL}, "n_clicks"),Input({"type": "bar-draggable", "length": ALL}, "n_clicks"),State("bar-config-display", "id"),State("bar-library", "id"),State("bar-store", "data"),prevent_initial_call=False
)# ====== Layout ======
app.layout = html.Div(style={'backgroundColor': COLORS['background'], 'color': COLORS['text'], 'fontFamily': 'Arial, sans-serif', 'padding': '20px'}, children=[html.H2("长条概率可视化工具", style={'textAlign': 'center', 'color': COLORS['primary'], 'marginBottom': '30px'}),html.Div([html.Label("矩阵大小 n:", style={'marginRight': '10px', 'fontSize': '18px'}),dcc.Input(id="matrix-size", type="number", value=4, min=2, max=10, step=1,style={'backgroundColor': COLORS['section_bg'], 'color': COLORS['text'], 'border': f'1px solid {COLORS["primary"]}', 'padding': '8px', 'borderRadius': '5px', 'width': '80px', 'textAlign': 'center'}),], style={"marginBottom": "30px", 'textAlign': 'center'}),html.Div([html.H3("长条库 (点击或拖动添加)", style={'color': COLORS['secondary'], 'marginBottom': '15px', 'textAlign': 'center'}),html.Div(id="bar-library", children=[html.Div(f"长条 {length}", id={'type': 'bar-draggable', 'length': length},draggable="true",n_clicks=0,style={'backgroundColor': COLORS['primary'], 'color': 'white', 'border': 'none','padding': '10px 15px', 'borderRadius': '5px', 'cursor': 'pointer', 'fontSize': '16px','transition': 'background-color 0.3s ease','boxShadow': '0 2px 4px rgba(0,0,0,0.2)'},className="draggable-bar")for length in range(1, 8)], style={'display': 'flex', 'gap': '10px', 'flexWrap': 'wrap', 'justifyContent': 'center', 'marginBottom': '30px'}),html.H3("已选长条配置", style={'color': COLORS['secondary'], 'marginBottom': '15px', 'textAlign': 'center'}),html.Div(id="bar-config-display",style={'border': f'1px dashed {COLORS["text"]}', 'padding': '15px', 'minHeight': '80px','borderRadius': '5px', 'display': 'flex', 'gap': '10px', 'flexWrap': 'wrap','alignItems': 'center', 'justifyContent': 'center'},className="drop-target-area"),dcc.Store(id="bar-store", data={}),dcc.Store(id="drag-drop-store", data={'last_dropped_length': None, 'timestamp': None}),], style={'marginBottom': '30px', 'border': f'1px solid {COLORS["section_bg"]}', 'padding': '20px', 'borderRadius': '8px', 'backgroundColor': COLORS['section_bg'], 'boxShadow': '0 4px 8px rgba(0,0,0,0.3)'}),dcc.Graph(id="matrix-graph", style={"height": "600px", 'border': f'1px solid {COLORS["section_bg"]}', 'borderRadius': '8px', 'backgroundColor': COLORS['section_bg'], 'boxShadow': '0 4px 8px rgba(0,0,0,0.3)'}),dcc.Store(id="evidence-store"),html.Div(id='dummy-output', style={'display': 'none'}),
])# ====== 生成矩阵图 ======
def create_matrix_figure(prob_matrix, evidence_matrix):n = len(prob_matrix)fig = go.Figure()fig.add_trace(go.Heatmap(z=prob_matrix,colorscale="Plasma",zmin=0, zmax=1,showscale=True,colorbar=dict(title=dict(text="概率", side="right", font=dict(color=COLORS['text'])),tickmode="array",tickvals=[0, 0.25, 0.5, 0.75, 1],ticktext=["0%", "25%", "50%", "75%", "100%"],len=0.75,thickness=20,x=1.02,y=0.5,outlinewidth=0,tickfont=dict(color=COLORS['text']))))annotations = []# 确保 max_prob 仅在 prob_matrix 不为空且不包含所有 NaN 时计算max_prob = np.max(prob_matrix) if prob_matrix.size > 0 and not np.all(np.isnan(prob_matrix)) else 0for i in range(n):for j in range(n):if evidence_matrix[i][j] == 1:text, color = "✔", COLORS['success']elif evidence_matrix[i][j] == -1:text, color = "✖", COLORS['danger']else:# 如果 prob_matrix 包含 NaN (例如由于错误), 显示空字符串if np.isnan(prob_matrix[i][j]):text = ""color = COLORS['text']else:text = f"{prob_matrix[i][j]:.2f}"color = COLORS['background'] if prob_matrix[i][j] > 0.7 else COLORS['text']annotations.append(dict(x=j, y=i, text=text, showarrow=False, font=dict(color=color, size=14)))# 仅在 max_prob 有意义时 (即不是所有零或 NaN) 高亮if evidence_matrix[i][j] == 0 and prob_matrix.size > 0 and not np.all(prob_matrix == 0) and abs(prob_matrix[i][j] - max_prob) < 1e-6:fig.add_shape(type="rect",x0=j-0.5, x1=j+0.5, y0=i-0.5, y1=i+0.5,line=dict(color=COLORS['warning'], width=3))fig.update_layout(annotations=annotations,xaxis=dict(scaleanchor="y", showgrid=False, zeroline=False, tickmode="linear", dtick=1, color=COLORS['text'],linecolor=COLORS['text'], mirror=True, showline=True),yaxis=dict(autorange="reversed", showgrid=False, zeroline=False, tickmode="linear", dtick=1, color=COLORS['text'],linecolor=COLORS['text'], mirror=True, showline=True),margin=dict(l=20, r=20, t=20, b=20),clickmode="event+select",plot_bgcolor=COLORS['background'],paper_bgcolor=COLORS['background'],font=dict(color=COLORS['text']))return fig# ====== 回调:处理长条选择/移除 ======
@app.callback(Output("bar-store", "data"),Output("bar-config-display", "children"),Input("drag-drop-store", "data"),Input({"type": "bar-remove-button", "length": ALL}, "n_clicks"),Input({"type": "bar-draggable", "length": ALL}, "n_clicks"),State("bar-store", "data"),prevent_initial_call=True
)
def handle_bar_selection(drag_drop_data, remove_clicks, add_clicks, current_bar_dict):ctx = callback_contextif not ctx.triggered:raise dash.exceptions.PreventUpdatebar_dict = current_bar_dict if current_bar_dict is not None else {}bar_dict = {int(k): int(v) for k, v in bar_dict.items()}triggered_prop = ctx.triggered[0]["prop_id"]# 拖拽添加if triggered_prop == "drag-drop-store.data":if drag_drop_data and drag_drop_data['last_dropped_length'] is not None:length = drag_drop_data['last_dropped_length']bar_dict[length] = bar_dict.get(length, 0) + 1# 移除按钮elif "bar-remove-button" in triggered_prop:triggered_dict = eval(triggered_prop.split(".")[0])length = triggered_dict["length"]if length in bar_dict:bar_dict[length] -= 1if bar_dict[length] <= 0:del bar_dict[length]# 点击添加elif "bar-draggable" in triggered_prop:triggered_dict = eval(triggered_prop.split(".")[0])length = triggered_dict["length"]bar_dict[length] = bar_dict.get(length, 0) + 1# 生成配置区显示display_children = []if not bar_dict:display_children.append(html.Span("拖动或点击长条库中的长条到此处添加", style={'color': COLORS['text'], 'fontStyle': 'italic'}))else:for length in sorted(bar_dict.keys()):count = bar_dict[length]display_children.append(html.Div([html.Span(f"长条 {length}: {count}个", style={'marginRight': '10px', 'fontWeight': 'bold', 'color': COLORS['text']}),html.Button("移除", id={'type': 'bar-remove-button', 'length': length}, n_clicks=0,style={'backgroundColor': COLORS['danger'], 'color': 'white', 'border': 'none','padding': '5px 10px', 'borderRadius': '3px', 'cursor': 'pointer', 'fontSize': '12px','transition': 'background-color 0.3s ease'})], style={'backgroundColor': COLORS['bar_item_bg'], 'padding': '8px 12px', 'borderRadius': '5px','display': 'flex', 'alignItems': 'center', 'gap': '5px', 'boxShadow': '0 1px 2px rgba(0,0,0,0.1)'}))return bar_dict, display_children# ====== 回调:更新矩阵显示 ======
@app.callback(Output("matrix-graph", "figure"),Output("evidence-store", "data"),Input("matrix-graph", "clickData"),Input("bar-store", "data"),Input("matrix-size", "value"),State("evidence-store", "data"),prevent_initial_call=False
)
def update_matrix(clickData, bar_dict, n, evidence_matrix_state):try:n = int(n)except Exception:n = 10triggered_id = callback_context.triggered[0]['prop_id'].split('.')[0] if callback_context.triggered else 'initial_load'if triggered_id == 'matrix-size' or evidence_matrix_state is None or len(evidence_matrix_state) != n:evidence_matrix = [[0] * n for _ in range(n)]else:evidence_matrix = [[int(v) for v in row] for row in evidence_matrix_state]if triggered_id == 'matrix-graph' and clickData:j, i = int(clickData["points"][0]["x"]), int(clickData["points"][0]["y"])if 0 <= i < n and 0 <= j < n:current = evidence_matrix[i][j]evidence_matrix[i][j] = -1 if current == 0 else 1 if current == -1 else 0prob_matrix = np.zeros((n, n)) # 默认零矩阵error_message = Noneif bar_dict:bar_dict_processed = {int(k): int(v) for k, v in bar_dict.items()}try:prob_matrix = compute_full_probability_matrix(n, bar_dict_processed, evidence_matrix, method="auto")except ValueError as e:# 捕获 numpy.random.choice 的特定 ValueError, 指示无有效放置方案error_message = f"计算错误: {e}. 当前长条配置或矩阵大小可能导致无有效放置方案。请检查长条长度和矩阵大小,或已标记的证据点。"print(f"Error computing probability matrix: {e}")# 将 prob_matrix 设置为 NaN 以视觉上指示错误, 或保持为零。# 使用 NaN 会使概率热图单元格为空。prob_matrix = np.full((n, n), np.nan)except Exception as e:# 捕获任何其他意外的计算错误error_message = f"发生未知计算错误: {e}."print(f"Unexpected error computing probability matrix: {e}")fig = create_matrix_figure(prob_matrix, evidence_matrix)if error_message:fig.add_annotation(text=error_message,xref="paper", yref="paper",x=0.5, y=0.5,showarrow=False,font=dict(size=16, color=COLORS['danger']),bgcolor="rgba(0,0,0,0.7)",bordercolor=COLORS['danger'],borderwidth=2,borderpad=10,align="center",)return fig, evidence_matrixif __name__ == "__main__":app.run(debug=True)

结语

以上就是全部内容了,欢迎大家互相讨论。


文章转载自:

http://6hQvZ9E4.nqxdg.cn
http://w0DDxQPb.nqxdg.cn
http://ki9gAxBa.nqxdg.cn
http://Cn5qWqxp.nqxdg.cn
http://Len1Q1q9.nqxdg.cn
http://5BvX4T94.nqxdg.cn
http://CKBSlrgL.nqxdg.cn
http://J6AJeg91.nqxdg.cn
http://YmzBAWqN.nqxdg.cn
http://zABmFEGg.nqxdg.cn
http://gIV1GdOx.nqxdg.cn
http://TQImdynT.nqxdg.cn
http://B8cT5itW.nqxdg.cn
http://uiiUb68r.nqxdg.cn
http://Ku1HiFTu.nqxdg.cn
http://2qFBQSdF.nqxdg.cn
http://A5IoUTkp.nqxdg.cn
http://IB36RMK2.nqxdg.cn
http://CcOgLP9j.nqxdg.cn
http://epuLDwGx.nqxdg.cn
http://RMmnfs72.nqxdg.cn
http://v1TkpVhQ.nqxdg.cn
http://B9KRLXuw.nqxdg.cn
http://32wTczH6.nqxdg.cn
http://5jzZjFSY.nqxdg.cn
http://CvCAnEzM.nqxdg.cn
http://1hxVa8bx.nqxdg.cn
http://9KAKAA80.nqxdg.cn
http://rL6o9AqE.nqxdg.cn
http://duz5ppp1.nqxdg.cn
http://www.dtcms.com/a/383511.html

相关文章:

  • 大模型入门实践指南
  • CSS 编码规范
  • Redis框架详解
  • Redis----缓存策略和注意事项
  • Redis的大key问题
  • 微服务学习笔记25版
  • 地址映射表
  • AI Agent 软件工程关键技术综述
  • 命令行工具篇 | grep, findstr
  • 6【鸿蒙/OpenHarmony/NDK】多线程调用 JS 总崩溃?用 napi_create_threadsafe_function 搞定线程安全交互
  • OpenTenBase分布式HTAP实战:从Oracle迁移到云原生数据库的完整指南
  • LabVIEW信号监测与分析
  • 【大模型算法工程师面试题】大模型领域新兴的主流库有哪些?
  • Java队列(从内容结构到经典练习一步到位)
  • Cherno OpenGL 教程
  • RT-DETRv2 中的坐标回归机制深度解析:为什么用 `sigmoid(inv_sigmoid(ref) + delta)` 而不是除以图像尺寸?
  • OpenCV入门教程
  • 深度学习-计算机视觉-目标检测三大算法-R-CNN、SSD、YOLO
  • 冰火两重天:AI重构下的IT就业图景
  • 从ENIAC到Linux:计算机技术与商业模式的协同演进——云原生重塑闭源主机,eBPF+WebAssembly 双引擎的“Linux 内核即服务”实践
  • 从 MySQL 迁移到 GoldenDB,上来就踩了一个坑。
  • qt界面开发入门以及计算器制作
  • SQL 核心概念与实践总结
  • 【Tourbox】怎么复制预设?
  • RTT操作系统(2)
  • 基于STM32单片机智能手表GSM短信上报GPS定位防丢器设计
  • 力扣658.找到K个最接近的元素
  • LeetCode 面试经典 150_哈希表_赎金信(39_383_C++_简单)
  • LeetCode热题100--114. 二叉树展开为链表--中等
  • 【交易系统系列33】从Raft到Kafka:解构交易所核心系统的一致性与数据持久化之道