PAT-B 1056. 组合数的和

本文介绍了一种快速计算由多个非0个位数字组成的全部两位数组合之和的方法。通过分析每位数字在组合中出现的位置及频次,利用数学公式简化了计算过程,实现了高效的求和算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目内容:

给定N个非0的个位数字,用其中任意2个数字都可以组合成1个2位的数字。要求所有可能组合出来的2位数字的和。例如给定2、5、8,则可以组合出:25、28、52、58、82、85,它们的和为330。

输入格式:

输入在一行中先给出N(1 < N < 10),随后是N个不同的非0个位数字。数字间以空格分隔。

输出格式:

输出所有可能组合出来的2位数字的和。

输入样例:

3 2 8 5

输出样例:

330

思路分析:

从题目叙述可以观察到,当有n个数字时,每个数字在十位和个位出现的次数均是n-1次,所以数字a对总和的贡献就是:
a×(n1)×(10+1)

代码:

#include<stdio.h>

int main() {
    int n = 0, sum = 0, a[10];
    scanf("%d", &n);
    for (int i = 0; i < n; i++) { // 计算所有数字的和
        scanf("%d", a+i);
        sum += a[i];
    }

    sum *= n - 1;

    printf("%d", sum * 11);
    return 0;
}

点这里进入试题网页

clear; clc; close all; %% ---------------- 1. 问题数据定义(含缺陷信息) ---------------- % 订单信息矩阵:[订单量(套), 宽度目标(m), 高度目标(m), 单价(元/套)] orders = [... 10, 1.6, 2.2, 480; % 订单1:学校教学楼 20, 1.8, 2.4, 680; % 订单2:酒店客房 20, 1.7, 2.3, 550; % 订单3:医院病房 15, 1.5, 2.0, 420]; % 订单4:政府办公楼 tol = 0.01; % 尺寸允许误差范围(±0.01m)types % 计算宽度高度的允许范围 width_ranges = [orders(:,2)-tol, orders(:,2)+tol]; height_ranges = [orders(:,3)-tol, orders(:,3)+tol]; % 整合所有边框类型的尺寸范围(8类:4宽+4高) border_info = zeros(8,2); for k = 1:size(orders,1) border_info(2*k-1, :) = width_ranges(k, :); % 宽度类型(1,3,5,7) border_info(2*k, :) = height_ranges(k, :); % 高度类型(2,4,6,8) end % 原材料信息(含缺陷):[长度(m), 单价(元/根)] materials = [ 5.5, 18; % 原材料1 6.2, 22; % 原材料2 7.8, 28]; % 原材料3 % 缺陷信息:每个单元格存储该类原材料的所有缺陷[起始置, 长度] defects = { [1.0, 0.03]; % 原材料1的缺陷 [2.5, 0.04]; % 原材料1的缺陷 [0.5, 0.02]; % 原材料2的缺陷 [1.8, 0.05]; % 原材料2的缺陷 [3.0, 0.03]; % 原材料3的缺陷 }; % 计算各原材料的可用区间(去除缺陷区域) available_segments = cell(3,1); % 存储每个原材料的可用区间[起始, 结束] for m = 1:3 L = materials(m,1); def = defects{m}; % 排序缺陷(按起始置) if ~isempty(def) def = sortrows(def, 1); % 计算缺陷结束置 def(:,2) = def(:,1) + def(:,2); end % 生成可用区间 segs = []; prev_end = 0; for d = 1:size(def,1) start_def = def(d,1); end_def = def(d,2); % 缺陷前的可用区间 if start_def > prev_end + 1e-12 segs = [segs; prev_end, start_def]; end prev_end = end_def; end % 最后一个缺陷到末端的可用区间 if prev_end < L - 1e-12 segs = [segs; prev_end, L]; end available_segments{m} = segs; end saw_width = 0.005; % 锯口宽度 max_cuts = 5; % 最大切割段数 % 材料需求总量 width_demand = 2 * orders(:,1); height_demand = 2 * orders(:,1); total_revenue = sum(orders(:,1) .* orders(:,4)); % 总收益 %% ---------------- 2. 生成含缺陷约束的切割模式 ---------------- patterns = []; % 存储所有可行切割模式 pidx = 0; % 模式编号 % 遍历每种原材料 for m = 1:size(materials,1) L = materials(m,1); segs = available_segments{m}; % 该原材料的可用区间 if isempty(segs) continue; % 无可用区间,跳过 end % 遍历每个可用区间 for s = 1:size(segs,1) seg_start = segs(s,1); seg_end = segs(s,2); seg_length = seg_end - seg_start; % 可用区间长度 % 遍历可能的切割段数 for n = 1:max_cuts % 生成切割类型组合 combos = multichoose(1:8, n); for r = 1:size(combos,1) types = combos(r, :); % 计算最小总长度(按最小允许尺寸)+ 锯口损失 min_len = sum(border_info(types,1)) + (n-1) * saw_width; % 检查是否能放入当前可用区间 if min_len <= seg_length + 1e-12 pidx = pidx + 1; patterns(pidx).material = m; % 原材料类型 patterns(pidx).segment = s; % 可用区间编号 patterns(pidx).segment_info = [seg_start, seg_end]; % 区间范围 % 统计各类型边框数量 cnt = zeros(1,8); for t = types cnt(t) = cnt(t) + 1; end patterns(pidx).counts = cnt; % 各类型数量 patterns(pidx).n = n; % 切割段数 patterns(pidx).types = types; % 边框类型列表 patterns(pidx).seg_length = seg_length; % 可用区间长度 end end end end end num_patterns = length(patterns); fprintf('共生成 %d 种可行切割模式(考虑缺陷)\n', num_patterns); %% ---------------- 3. 建立整数规划模型并求解 ---------------- % 转换模式信息为矩阵 all_patterns = zeros(num_patterns, 11); % 增加一列存储可用区间编号 for i = 1:num_patterns all_patterns(i,1) = patterns(i).material; % 原材料类型 all_patterns(i,2) = patterns(i).segment; % 可用区间编号 all_patterns(i,3:10) = patterns(i).counts; % 8类边框数量 all_patterns(i,11) = patterns(i).n; % 切割段数 end % 目标函数:最小化总成本 f = zeros(num_patterns,1); for i = 1:num_patterns m = all_patterns(i,1); f(i) = materials(m,2); % 原材料单价 end % 约束矩阵:满足各类型边框需求 A = all_patterns(:, 3:10)'; % 8类边框的产量矩阵 b = zeros(8,1); for k = 1:4 b(2*k-1) = width_demand(k); % 宽度需求 b(2*k) = height_demand(k); % 高度需求 end % 整数规划参数 intcon = 1:num_patterns; % 整数变量 lb = zeros(num_patterns,1); % 下界 ub = inf(num_patterns,1); % 上界 % 求解 options = optimoptions('intlinprog', 'Display', 'off'); [x, exitflag] = intlinprog(f, intcon, -A, -b, [], [], lb, ub, options); if exitflag <= 0 warning('intlinprog 未找到最优解,进行手动调整'); end % 处理求解结果 x = round(x); produced = A * x; % 确保满足需求 if any(produced < b) deficit = b - produced; while any(deficit > 0) j = find(deficit > 0, 1); candidates = find(all_patterns(:,2+j) > 0); if ~isempty(candidates) best_p = candidates(1); x(best_p) = x(best_p) + 1; produced = A * x; deficit = b - produced; else error('无可用模式满足需求,请检查参数'); end end end used_patterns = find(x > 0); %% ---------------- 4. 统计结果与指标计算 ---------------- total_saw_loss = 0; % 总锯口损失 total_cut_length = 0; % 总切割长度 material_usage = zeros(size(materials,1),1); % 原材料使用根数 total_defect_length = 0; % 缺陷导致的损失长度 % 计算每种原材料的总缺陷长度 material_defect_length = zeros(3,1); for m = 1:3 def = defects{m}; material_defect_length(m) = sum(def(:,2)); % 缺陷总长度 end % 遍历所有使用的模式 for i = used_patterns' cnt_inst = x(i); % 使用次数 pat = patterns(i); m = pat.material; % 原材料类型 L = materials(m,1); ncuts = pat.n; % 切割段数 types_template = pat.types; seg_length = pat.seg_length; % 可用区间长度 % 累加原材料使用量缺陷损失 material_usage(m) = material_usage(m) + cnt_inst; total_defect_length = total_defect_length + cnt_inst * material_defect_length(m); % 计算每根的切割细节 for inst = 1:cnt_inst [seg_lengths, leftover] = fit_segment_lengths(types_template, orders, border_info, seg_length, saw_width); total_cut_length = total_cut_length + sum(seg_lengths); total_saw_loss = total_saw_loss + (ncuts - 1) * saw_width; end end % 核心指标计算 total_material_length = sum(material_usage .* materials(:,1)); % 原材料总长度 total_used_effective = total_cut_length + total_saw_loss; % 有效使用长度(含锯口) total_remaining = total_material_length - (total_used_effective + total_defect_length); % 余料 utilization = total_used_effective / total_material_length; % 利用率(有效长度/总长度) loss_rate = 1 - utilization; % 总损失率 % 经济指标 total_cost = material_usage' * materials(:,2); % 总成本 profit = total_revenue - total_cost; % 总利润 %% ---------------- 5. 输出结果 ---------------- fprintf('\n===== 含缺陷的最优切割方案结果 =====\n'); fprintf('总收益: %.2f 元\n', total_revenue); fprintf('总成本: %.2f 元\n', total_cost); fprintf('总利润: %.2f 元\n', profit); fprintf('总原材料长度: %.2f 米\n', total_material_length); fprintf('有效使用长度: %.2f 米\n', total_used_effective); fprintf('缺陷损失长度: %.2f 米\n', total_defect_length); fprintf('余料长度: %.2f 米\n', total_remaining); fprintf('利用率: %.2f%%\n', utilization*100); fprintf('损失率: %.2f%%\n', loss_rate*100); %% ---------------- 6. 可视化展示 ---------------- % 图1:原材料使用数量 figure; bar(material_usage); xticklabels(arrayfun(@(v) sprintf('%.1fm',v), materials(:,1), 'UniformOutput', false)); ylabel('使用根数'); title('各类原材料使用数量(含缺陷)'); grid on; % 图2:材料分配比例(含缺陷) figure; pie([total_cut_length, total_saw_loss, total_defect_length, max(total_remaining,0)], ... {'边框总长度','锯缝损失','缺陷损失','余料'}); title('材料分配比例(含缺陷)'); % 图3:切割模式示意图(标注缺陷) colors = lines(8); % 边框类型颜色 figure('Name','含缺陷的切割模式示意图','Position',[100,100,1400,900]); y_gap = 1.5; y_pos = 0; % 按原材料分组展示 for m = 1:3 L = materials(m,1); def = defects{m}; segs = available_segments{m}; % 筛选该原材料的使用模式 m_patterns = used_patterns(all_patterns(used_patterns,1) == m); % 绘制原材料标题 title_text = sprintf('原材料 %.1fm(含缺陷)', L); text(L/2, y_pos + 1.5, title_text, 'FontWeight','bold', 'FontSize',12, ... 'HorizontalAlignment','center', 'VerticalAlignment','bottom'); y_pos = y_pos + 2; % 绘制原材料基线缺陷 % 基线 plot([0, L], [y_pos, y_pos], 'k-', 'LineWidth',1); % 缺陷区域 for d = 1:size(def,1) def_start = def(d,1); def_len = def(d,2); def_end = def_start + def_len; patch([def_start, def_end, def_end, def_start], ... [y_pos-0.2, y_pos-0.2, y_pos+0.2, y_pos+0.2], [1,0.3,0.3], ... 'EdgeColor','k', 'FaceAlpha',0.7); % 红色标注缺陷 end y_pos = y_pos + 1; % 绘制可用模式 if ~isempty(m_patterns) for p_idx = 1:length(m_patterns) pat_id = m_patterns(p_idx); pat = patterns(pat_id); seg_idx = pat.segment; seg = segs(seg_idx,:); seg_start = seg(1); seg_end = seg(2); % 绘制模式标题 text(seg_start-0.1, y_pos+0.5, sprintf('模式 %d (×%d)', pat_id, x(pat_id)), ... 'HorizontalAlignment','right', 'FontSize',9); % 绘制切割段 xpos = seg_start; for s = 1:length(pat.types) t = pat.types(s); % 确定边框长度 if mod(t-1,2) == 0 seg_len = orders(floor((t-1)/2)+1, 2); else seg_len = orders(floor((t-1)/2)+1, 3); end % 绘制边框段 patch([xpos, xpos+seg_len, xpos+seg_len, xpos], ... [y_pos-0.3, y_pos-0.3, y_pos+0.3, y_pos+0.3], colors(t,:), ... 'EdgeColor','k'); xpos = xpos + seg_len; % 绘制锯口 if s < length(pat.types) patch([xpos, xpos+saw_width, xpos+saw_width, xpos], ... [y_pos-0.3, y_pos-0.3, y_pos+0.3, y_pos+0.3], [0.4 0.4 0.4], ... 'EdgeColor','none', 'FaceAlpha',0.4); xpos = xpos + saw_width; end end y_pos = y_pos + y_gap; end else text(L/2, y_pos, '无使用模式', 'HorizontalAlignment','center', 'Color',[0.6 0.6 0.6]); y_pos = y_pos + 2; end y_pos = y_pos + 2; % 组间间隔 end % 坐标轴设置 xlim([0, max(materials(:,1))+0.5]); ylim([0, y_pos]); xlabel('长度 (米)'); ylabel('切割模式'); title('含缺陷原材料的切割模式示意图(红色为缺陷区域)'); % 图例 hold on; h_legend = gobjects(9,1); for t = 1:8 h_legend(t) = plot(nan, nan, 's', 'MarkerFaceColor', colors(t,:), ... 'MarkerEdgeColor','k', 'MarkerSize', 10); end h_legend(9) = plot(nan, nan, 's', 'MarkerFaceColor', [1,0.3,0.3], ... 'MarkerEdgeColor','k', 'MarkerSize', 10); legend(h_legend, {'订单1宽','订单1高','订单2宽','订单2高','订单3宽','订单3高','订单4宽','订单4高','缺陷区域'}, ... 'Location','eastoutside'); grid on; %% ---------------- 辅助函数 ---------------- % 生成可重复组合 function combos = multichoose(pool, n) if n == 0 combos = []; return; end if n == 1 combos = pool(:); return; end combos = []; for i = 1:length(pool) head = pool(i); tail_pool = pool(i:end); sub = multichoose(tail_pool, n-1); combos = [combos; [repmat(head, size(sub,1), 1), sub]]; end end % 计算切割段实际长度 function [seg_lengths, leftover] = fit_segment_lengths(types, orders, border_info, seg_length, saw_width) n = length(types); targets = zeros(1,n); mins = zeros(1,n); for k = 1:n t = types(k); order_idx = floor((t-1)/2)+1; if mod(t-1,2) == 0 targets(k) = orders(order_idx, 2); else targets(k) = orders(order_idx, 3); end mins(k) = border_info(t,1); end kerf = (n - 1) * saw_width; total_target = sum(targets); if total_target + kerf <= seg_length + 1e-12 seg_lengths = targets; leftover = seg_length - (sum(seg_lengths) + kerf); return; end need = total_target + kerf - seg_length; allowed_reduction = targets - mins; seg_lengths = targets; [sorted_vals, idxs] = sort(allowed_reduction, 'descend'); rem = need; for ii = 1:length(idxs) j = idxs(ii); red = min(sorted_vals(ii), rem); seg_lengths(j) = seg_lengths(j) - red; rem = rem - red; if rem <= 1e-12 break; end end leftover = seg_length - (sum(seg_lengths) + kerf); if leftover < 0 && leftover > -1e-8 leftover = 0; end end 这个代码运行不出来了,帮我改一下
最新发布
08-12
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值