To Bet or Not To Bet

博客内容讲述了如何使用动态规划解决一个涉及概率计算的移动指令问题。代码中,作者详细解析了动态规划矩阵的更新过程,特别是对于移动一步或两步后是否停留的情况进行了深入解释,以计算在给定步数限制内到达终点的概率。最终,根据概率输出是否下注的建议。

To Bet or Not To Bet

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
又是一道细节满满的题,一个不留神就不能通过。。。找 bug 找好长时间,这是一道动态规划的题,我们将输入的指令全部转化为数值命令,便于我们操作,下面我重点解释一下概率的计算的循环过程,其余的已经写在注释里了,关于代码:

for (int i = 0;i <= t;i++) {//注意下标,i=0 表示从 0 步开始计步,j=0 表示从起点开始 
	for (int j = 0;j <= m;j++) {//这一段循环我在外面说明哦~ 
		if (step[j + 1] == inf) dp[i + 2][j + 1] += dp[i][j] * 0.5;
		else dp[i + 1][j + 1 + step[j + 1]] += dp[i][j] * 0.5;
		if (step[j + 2] == inf) dp[i + 2][j + 2] += dp[i][j] * 0.5;
		else dp[i + 1][j + 2 + step[j + 2]] += dp[i][j] * 0.5;
	}
}

说明:首先点明 if 与 else 需要不同的理解方式,先看 if:它是说移动一位或者两位到达的地方要停一轮,所以说相当于第 i+2 轮移动到了这里,那么你可能要问:第 i+1 轮已经来到这里了呀,只不过是停了一轮罢了,那第 i+1 的概率哪去了??如果说我们的代码正确的话,那么我们只能说在 else 中了,没错!因为移动一轮之后step[j + 1] == inf的判断条件实际上变成了step[j + 2] == inf(当前终点成为下一次的起点!)!也就是另一种判断情况了!!这个弯得绕过来!所以我们理解了 if 语句的合理性。
下面是 else:从当前出发到达 j+1 or j+2,但还是没有停下!因为要执行指令,所以说从 j 来到了 j + 1 + step[j + 1] 或者 j + 2 + step[j + 2],并且只是多移动了一轮!(没有停一轮),这样就不难理解代码了:

//概率动态规划(主要是希望逐渐掌握动态规划) 
#include<iostream>
#include<cstdio>
#include<cstring>
#define inf 0x7fffffff//用最大数表示停一轮 
using namespace std;
int n, m, t;//n 个测试用例,m 个格子(除了起点与终点),最多 t 轮 
char s[10];//存放移动指令 
int step[55];//将移动指令转化为数值 
double dp[55][55];//dp[i][j] 表示第 i 次移动到位置 j 处 
int main() {
	cin >> n;
	while (n--) {//进行 n 轮 
		cin >> m >> t;
		memset(dp, 0, sizeof(dp));//每一轮初始化为 0 
		memset(step, 0, sizeof(step));
		for (int i = 1;i <= m;i++) {//注意从 1 到 m 时 step 才有意义 
			scanf("%s", s);
			//将 s 翻译成 step: 
			if (s[0] == '0') step[i] = 0;
			else if (s[0] == 'L') step[i] = inf;//特判 0,因为没有 + - 符号! 
			else {
				for (int j = 1;s[j] != '\0';j++) step[i] = step[i] * 10 + s[j] - '0';//对绝对值为 10 以上的数发挥作用 
				if (s[0] == '-') step[i] *= (-1);
			}
		}
		dp[0][0] = 1;//一定要记得初始化起点!!! 
		step[m + 2] = -1;//这里表示由 m+2 退回 m+1(到达终点) 
		for (int i = 0;i <= t;i++) {//注意下标,i=0 表示从 0 步开始计步,j=0 表示从起点开始 
			for (int j = 0;j <= m;j++) {//这一段循环我在外面说明哦~ 
				if (step[j + 1] == inf) dp[i + 2][j + 1] += dp[i][j] * 0.5;
				else dp[i + 1][j + 1 + step[j + 1]] += dp[i][j] * 0.5;
				if (step[j + 2] == inf) dp[i + 2][j + 2] += dp[i][j] * 0.5;
				else dp[i + 1][j + 2 + step[j + 2]] += dp[i][j] * 0.5;
			}
		}
		for (int i = 0;i < t;i++) dp[t][m + 1] += dp[i][m + 1];//计算总概率 
		if (dp[t][m + 1] == 0.5) printf("Push. 0.5000\n");
		else if (dp[t][m + 1] < 0.5) printf("Bet against. %.4lf\n", dp[t][m + 1]);
		else printf("Bet for. %.4lf\n", dp[t][m + 1]);
	}
	return 0;
}
修复一下这个函数 新增一个字段, 输赢整数 # 赔付状态 -1:闲输 1:正常赔付玩家赢 2 部分赔付玩家赢 3 喝水赔付玩家赢 def calculate_winning(agent_id, draw_period, winning_numbers, return_principal_on_loss=True): """ 计算某一期所有投注的赔付结果,并在结果中包含 username 和 balance :param agent_id: 代理ID :param draw_period: 期号 :param winning_numbers: 开奖号码(格式如 "7,8,6,9") :param mysql: MySQL 数据库连接对象 :param return_principal_on_loss: 是否在部分赔付时返还本金(默认 True) :return: 赔付明细列表,每个条目包含 user_id, username, bet_amount, win_amount, status, balance 等字段 """ cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor) #cursor = mysql.cursor(dictionary=True) #这个可以调试 # 1. 获取投注记录并结合 users 表获取 username 和 balance query_bets = """ SELECT b.*, u.username, u.balance FROM bets b JOIN users u ON b.user_id = u.id WHERE b.agent_id = %s AND b.draw_period = %s """ cursor.execute(query_bets, (agent_id, draw_period)) bets = cursor.fetchall() if not bets: print("没有找到相关下注记录") return [] # 2. 获取庄家信息 query_bank = """ SELECT * FROM banks WHERE agent_id = %s """ cursor.execute(query_bank, (agent_id,)) bank = cursor.fetchone() if not bank: print("没有找到对应庄家信息") return [] bank_balance = float(bank['balance']) # 3. 获取赔率配置 query_agent = """ SELECT odds_settings FROM agents WHERE id = %s """ cursor.execute(query_agent, (agent_id,)) agent = cursor.fetchone() if not agent or not agent['odds_settings']: print("代理配置缺失") return [] odds_settings = json.loads(agent['odds_settings'])["赔率_限红"] code_to_odds = {} code_to_tie_rule = {} for key in odds_settings: point_code = str(odds_settings[key]['代码']) code_to_odds[point_code] = float(odds_settings[key]['赔率']) code_to_tie_rule[point_code] = bool(odds_settings[key].get('同点庄赢', False)) # 4. 解析开奖号码 try: winning_list = [int(num) for num in winning_numbers.split(',')] except: print("开奖号码格式错误") return [] if len(winning_list) < 2: print("开奖号码数据不完整") return [] banker_point = int(winning_list[0]) player_points = [int(p) for p in winning_list[1:]] # 5. 按 bet_type 分组 def get_player_index(bet): try: return int(bet['bet_type'].replace('门', '')) except: return -1 bets_by_position = {} for bet in bets: pos = get_player_index(bet) if pos not in bets_by_position: bets_by_position[pos] = [] bets_by_position[pos].append(bet) # 6. 构造有效门次并排序 valid_positions = [ (idx + 1, player_points[idx]) for idx in range(len(player_points)) if (idx + 1) in bets_by_position ] sorted_positions = sorted(valid_positions, key=lambda x: x[1], reverse=True) results = [] # 7. 先杀阶段:比庄小或平局 print("【第一阶段】开始:先杀(比庄小或平局)") for idx, player_point in enumerate(player_points, start=1): if idx not in bets_by_position: continue current_bets = bets_by_position.get(idx, []) for bet in current_bets: amount = float(bet['amount']) user_id = bet['user_id'] username = bet['username'] balance = float(bet['balance']) # 用户原始余额 bet_code = str(player_point) if player_point < banker_point: # 比庄小,输 bank_balance += amount total_win = 0 if not return_principal_on_loss else amount status = "输(先杀)" reason = f"玩家点数 {player_point} 小于庄家点数 {banker_point}" results.append({ "user_id": user_id, "username": username, "bet_amount": amount, "win_amount": total_win, "odds": 0, "status": status, "reason": reason, "balance": balance + total_win }) update_query = "UPDATE bets SET win_amount = %s WHERE id = %s" cursor.execute(update_query, (total_win, bet['id'])) # 新增:更新用户余额 update_user_balance_query = "UPDATE users SET balance = %s WHERE id = %s" cursor.execute(update_user_balance_query, (balance + total_win, user_id)) elif player_point == banker_point: tie_rule = code_to_tie_rule.get(bet_code, False) if tie_rule: max_payout = amount * code_to_odds.get(bet_code, 1.0) if bank_balance >= max_payout: win_amount = max_payout bank_balance -= win_amount total_win = win_amount status = "正常赔付(平局且闲赢)" reason = f"平局,但赔率配置允许闲赢,赔付 {max_payout:.2f}" elif bank_balance > 0: win_amount = bank_balance bank_balance -= win_amount total_win = win_amount if return_principal_on_loss: total_win += amount status = "部分赔付(平局且闲赢)" reason = f"平局,但庄家余额不足,赔付 {win_amount:.2f}" + ( f",返还本金 {amount:.2f}" if return_principal_on_loss else "") else: total_win = amount if return_principal_on_loss else 0 status = "喝水赔付(返还本金)" reason = "平局且庄家无余额,仅返还本金" results.append({ "user_id": user_id, "username": username, "bet_amount": amount, "win_amount": total_win, "odds": code_to_odds.get(bet_code, 1.0), "status": status, "reason": reason, "balance": balance + total_win }) update_query = "UPDATE bets SET win_amount = %s WHERE id = %s" cursor.execute(update_query, (total_win, bet['id'])) # 新增:更新用户余额 update_user_balance_query = "UPDATE users SET balance = %s WHERE id = %s" cursor.execute(update_user_balance_query, (balance + total_win, user_id)) else: bank_balance += amount total_win = 0 if not return_principal_on_loss else amount results.append({ "user_id": user_id, "username": username, "bet_amount": amount, "win_amount": total_win, "odds": 0, "status": "输(平局且庄赢)", "reason": f"平局且赔率配置规定庄赢,没收投注金额 {amount:.2f}", "balance": balance + total_win }) update_query = "UPDATE bets SET win_amount = %s WHERE id = %s" cursor.execute(update_query, (total_win, bet['id'])) # 新增:更新用户余额 update_user_balance_query = "UPDATE users SET balance = %s WHERE id = %s" cursor.execute(update_user_balance_query, (balance + total_win, user_id)) print(f"当前庄家余额:{bank_balance:.2f}") # 8. 后赔阶段:从高到低赔付 print("【第二阶段】开始:后赔(点数从高到低)") for idx, player_point in sorted_positions: if player_point <= banker_point: continue current_bets = bets_by_position.get(idx, []) for bet in current_bets: amount = float(bet['amount']) user_id = bet['user_id'] username = bet['username'] balance = float(bet['balance']) # 原始余额 bet_code = str(player_point) odds = code_to_odds.get(bet_code, 1.0) max_payout = amount * odds if bank_balance >= max_payout: win_amount = max_payout bank_balance -= win_amount total_win = win_amount status = "正常赔付" reason = f"玩家点数 {player_point} 大于庄家点数 {banker_point},赔付 {win_amount:.2f}" elif bank_balance > 0: win_amount = bank_balance bank_balance -= win_amount total_win = win_amount if return_principal_on_loss: total_win += amount status = "部分赔付(庄家余额不足)" reason = f"玩家点数 {player_point} 大于庄家点数 {banker_point},但庄家余额不足,赔付 {win_amount:.2f}" + ( f",返还本金 {amount:.2f}" if return_principal_on_loss else "" ) else: total_win = amount if return_principal_on_loss else 0 status = "喝水赔付(返还本金)" reason = "玩家点数大于庄家,但庄家无余额,仅返还本金" new_balance = balance + total_win results.append({ "user_id": user_id, "username": username, "bet_amount": amount, "win_amount": total_win, "odds": odds if total_win != amount else 1.0, "status": status, "reason": reason, "balance": new_balance, "player_point":player_point }) update_query = "UPDATE bets SET win_amount = %s WHERE id = %s" cursor.execute(update_query, (total_win, bet['id'])) # 新增:更新用户余额 update_user_balance_query = "UPDATE users SET balance = %s WHERE id = %s" cursor.execute(update_user_balance_query, (new_balance, user_id)) print(f"门次:{idx}, 点数:{player_point}, 当前庄家余额:{bank_balance:.2f}") if bank_balance <= 0: print("庄家余额已耗尽,后续投注仅返还本金(喝水)") # 9. 更新庄家余额 update_bank_query = "UPDATE banks SET balance = %s WHERE id = %s" cursor.execute(update_bank_query, (bank_balance, bank['id'])) cursor.close() print(f"\n最终庄家余额:{bank_balance:.2f}") print(f"赔付明细:\n{json.dumps(results, indent=4, ensure_ascii=False)}") return format_payout_result(results, draw_period)
07-02
PS F:\mindpower2025\ruoyi-ui> npm install npm warn EBADENGINE Unsupported engine { npm warn EBADENGINE package: '@achrinza/node-ipc@9.2.2', npm warn EBADENGINE required: { node: '8 || 10 || 12 || 14 || 16 || 17' }, npm warn EBADENGINE current: { node: 'v18.20.8', npm: '10.8.2' } npm warn EBADENGINE } npm warn EBADENGINE Unsupported engine { npm warn EBADENGINE package: '@achrinza/node-ipc@9.2.2', npm warn EBADENGINE required: { node: '8 || 10 || 12 || 14 || 16 || 17' }, npm warn EBADENGINE current: { node: 'v18.20.8', npm: '10.8.2' } npm warn EBADENGINE } npm warn deprecated q@1.5.1: You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. npm warn deprecated npm warn deprecated (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) npm warn deprecated lodash.isequal@4.5.0: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. npm warn deprecated uuid@3.4.0: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. npm warn deprecated highlight.js@9.18.5: Support has ended for 9.x series. Upgrade to @latest npm warn deprecated rimraf@2.7.1: Rimraf versions prior to v4 are no longer supported npm warn deprecated rimraf@2.7.1: Rimraf versions prior to v4 are no longer supported npm warn deprecated uuid@3.4.0: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. npm warn deprecated rimraf@2.7.1: Rimraf versions prior to v4 are no longer supported npm warn deprecated uuid@3.4.0: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. npm warn deprecated rimraf@2.7.1: Rimraf versions prior to v4 are no longer supported npm warn deprecated rimraf@2.7.1: Rimraf versions prior to v4 are no longer supported npm warn deprecated rimraf@2.7.1: Rimraf versions prior to v4 are no longer supported npm warn deprecated rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported npm warn deprecated uuid@3.4.0: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. npm warn deprecated svgo@1.3.2: This SVGO version is no longer supported. Upgrade to v2.x.x. npm warn deprecated svgo@1.3.2: This SVGO version is no longer supported. Upgrade to v2.x.x. npm warn deprecated core-js@2.6.12: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. added 154 packages, removed 2142 packages, changed 246 packages, and audited 5521 packages in 5m 153 packages are looking for funding run `npm fund` for details 95 vulnerabilities (4 low, 61 moderate, 22 high, 8 critical) To address issues that do not require attention, run: npm audit fix To address all issues possible (including breaking changes), run: npm audit fix --force Some issues need review, and may require choosing a different dependency. Run `npm audit` for details. npm notice npm notice New major version of npm available! 10.8.2 -> 11.6.0 npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.6.0 npm notice To update run: npm install -g npm@11.6.0 npm notice
09-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值