gusucode.com > 《matlab在数学建模中的应用》一书 所有的 源代码 > 第10章/P10-1/main.m

    % 功能说明:
%     根据参考答案中的模型,本程序分别对
%     K1、K2、K3、K4型彩票进行求解,并对
%     n、m的各种组合进行循环。求解时,首先
%     计算当前n、m的各奖项获奖概率,然后
%     随机生成多个初始值,调用fmincon函数
%     寻找目标函数的最小值(原目标函数要求
%     极大,但fmincon是寻找极小,故令原目标
%     函数乘以(-1),寻找新目标函数的极小值),
%     最后比较各种类型彩票的求解结果,输出
%     对应最大的原目标函数的解。
% 本程序包含的m文件为:
%     main.m:主程序
%     cpiao.m:目标函数
%     calculate_probability.m:计算各奖项获奖概率
%     nonlcon.m:非线性约束
% 使用说明:
%    执行main.m

clc
clear

% 为避免陷入局部最优,需要以随机的初值进行多次尝试,
% 该变量为对每个m/n组合生成随机初值的数目,越大则找到
% 全局最优的概率越大,但程序运行的时间也越长,
% 请根据电脑情况自行设置
nums_test_of_initial_value = 20; 

global v
v = 630589;		% 求解v为630589的收入水平情况
DEBUG = 0;
rand('state',sum(100*clock))	% 初始化随机数生成器
format long g

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 求解开始
% 对于K1型
p_k1 = [2e-7;8e-7;1.8e-5;2.61e-4;3.42e-3;4.1995e-2];
% 6个奖项6个变量
Aeq=[1,1,1,0,0,0];
beq=1;
a_lb=[10,4,3,4,2];
b_ub=[233,54,17,20,10];
A= [0,0,0,-1,a_lb(4),0;
    0,0,0,1,-b_ub(4),0;
    0,0,0,0,-1,a_lb(5);
    0,0,0,0,1,-b_ub(5)];
b= [0;0;0;0];
lb=[0.5;0;0;0;0;0];
ub=[0.8;1;1;inf;inf;inf];
p_test = p_k1;
rx0_tmp = zeros(6,1);
rx_meta_result = zeros(6,1);
fval_meta_result = inf;
flag_meta_result = nan; %用以判断有没有得到过可行解
if DEBUG == 1
    output_meta_result = [];
end
for j = 1:nums_test_of_initial_value
    %随机生成多个初始值rx0_tmp,以避免局部最优
    rx0_tmp(1) = rand*(0.8-0.5) + 0.5;
    rx0_tmp(2) = rand*(1-rx0_tmp(1));
    rx0_tmp(3) = 1 - rx0_tmp(1) - rx0_tmp(2);
    rx0_tmp(4) = rand*1000;
    rx0_tmp(5) = rand*100;
    rx0_tmp(6) = rand*50;
    % 寻优
    [rx_tmp,fval_tmp,flag_tmp,output_tmp]= ...
            fmincon('cpiao',rx0_tmp,A,b,...
                    Aeq,beq,lb,ub,'nonlcon',[],1,p_test,a_lb,b_ub);
	% 上式倒数第四个参数是为了区分彩票的类型(K1/K2/K3/K4)
	% 最后三个是函数cpiao和nonlcon计算中可能要用到的量。
    if (flag_tmp == 1) && (fval_meta_result > fval_tmp)
        fval_meta_result = fval_tmp;
        rx_meta_result = rx_tmp;
        flag_meta_result = 1;
        if DEBUG == 1
            output_meta_result = output_tmp;
        end
    end
end
% 把求得的最好结果保存下来
if ~isnan(flag_meta_result)
    rx_k1 = rx_meta_result;
    fval_k1 = fval_meta_result;
    flag_k1 = flag_meta_result;
    if DEBUG == 1
        output = output_meta_result;
    end
else
    if DEBUG == 1
        rx_k1 = rx_tmp;
        fval_k1 = fval_tmp;
        flag_k1 = flag_tmp;
        output = output_tmp;
    end
end

% 对于K2、K3、K4型的情况
% n选m或(m+1),n的选择范围在29到60,m的选择范围为5到7
% 故有 (60-29+1)*(7-5+1)=96种 取法,
% 依题意,K2、K3、K4都有这96种取法,也即第三维上为3
% 故有下面的变量声明:
p_all=zeros(7,96,3);
rx_all = zeros(7,96,3);
fval_all= zeros(1,96,3);
flag_all = zeros(1,96,3);
for m=5:7
    for n=29:60
        for i=1:3
            % 根据i的值判断属于(K2、K3、K4)中哪一型
            % (i=1是K2;i=2是K3;i=3是K4),
            % 并根据n、m生成各奖项概率
            % p_temp=eval(sprintf('comb_k%d(m,n)',i+1));
			p_temp = calculate_probability(m,n,i+1);
            p_all(:,(m-5).*32+(n-28),i) = p_temp;
            % K2、K3可合并处理(奖项数目一样)
            if (i ~= 3)
                Aeq=[1,1,1,0,0,0,0];
                beq=1;
                a_lb=[10,4,3,4,2,2];
                b_ub=[233,54,17,20,10,10];
                A=[ 0,0,0,-1,a_lb(4),0,0;
                    0,0,0,1,-b_ub(4),0,0;
                    0,0,0,0,-1,a_lb(5),0;
                    0,0,0,0,1,-b_ub(5),0];
                %由于x(7)可能为零,故不在这里对x(6)/x(7)进行上下限限制,
                % 而在非线性约束nonlcon中进行
                %    0,0,0,0,0,-1,a_lb(6);
                %    0,0,0,0,0,1,-b_ub(6)];
                %b=[0;0;0;0;0;0];
                b=[0;0;0;0];
                lb=[0.5;0;0;0;0;0;0];
                ub=[0.8;1;1;inf;inf;inf;inf];
                p_test = p_temp;
                %随机生成多个初始值rx0_tmp,以避免局部最优
                rx0_tmp = zeros(7,1);
                rx_meta_result = zeros(7,1);
                fval_meta_result = inf;
                flag_meta_result = nan; %用以判断有没有得到过可行解
                for j = 1:nums_test_of_initial_value
                    rx0_tmp(1) = rand*(0.8-0.5) + 0.5;
                    rx0_tmp(2) = rand*(1-rx0_tmp(1));
                    rx0_tmp(3) = 1 - rx0_tmp(1) - rx0_tmp(2);
                    rx0_tmp(4) = rand*1000;
                    rx0_tmp(5) = rand*100;
                    rx0_tmp(6) = rand*50;
                    rx0_tmp(7) = rand*10;
                    [rx_tmp,fval_tmp,flag_tmp]= ...
                            fmincon('cpiao',rx0_tmp,...
                                    A,b,Aeq,beq,lb,ub,...
										'nonlcon',[],i+1,p_test,a_lb,b_ub);
					% 上式倒数第四个参数是为了区分彩票的类型(K1/K2/K3/K4)
					% 最后三个是函数cpiao和nonlcon计算中可能要用到的量。
                    if (flag_tmp == 1) && (fval_meta_result > fval_tmp)
                        fval_meta_result = fval_tmp;
                        rx_meta_result = rx_tmp;
                        flag_meta_result = 1;
                    end
                end
                % 把求得的最好结果保存下来
                rx_all(:,(m-5).*32+(n-28),i) = rx_meta_result;
                fval_all(1,(m-5).*32+(n-28),i) = fval_meta_result;
                flag_all(1,(m-5).*32+(n-28),i) = flag_meta_result;
            else
            % i==3,相应于K4型
                % 对于K4型,因只设到五等奖,故仅5个变量了
                Aeq=[1,1,1,0,0];
                beq=1;
                a_lb=[10,4,3,4];
                b_ub=[233,54,17,20];
                A=[ 0,0,0,-1,a_lb(4);
                    0,0,0,1,-b_ub(4)];
                b=[0;0];
                lb=[0.5;0;0;0;0];
                ub=[0.8;1;1;inf;inf];
                p_test = p_temp;
                %随机生成多个初始值rx0_tmp,以避免局部最优
                rx0_tmp = zeros(5,1);
                rx_meta_result = zeros(5,1);
                fval_meta_result = inf;
                flag_meta_result = nan; %用以判断有没有得到过可行解
                for j = 1:nums_test_of_initial_value
                    rx0_tmp(1) = rand*(0.8-0.5) + 0.5;
                    rx0_tmp(2) = rand*(1-rx0_tmp(1));
                    rx0_tmp(3) = 1 - rx0_tmp(1) - rx0_tmp(2);
                    rx0_tmp(4) = rand*1000;
                    rx0_tmp(5) = rand*100;
                    [rx_tmp,fval_tmp,flag_tmp]= ...
                            fmincon('cpiao',rx0_tmp,A,b,...
                                    Aeq,beq,lb,ub,'nonlcon',...
										[],4,p_test,a_lb,b_ub);
					% 上式倒数第四个参数是为了区分彩票的类型(K1/K2/K3/K4)
					% 最后三个是函数cpiao和nonlcon计算中可能要用到的量。
                    if (flag_tmp == 1) && (fval_meta_result > fval_tmp)
                        fval_meta_result = fval_tmp;
                        rx_meta_result = rx_tmp;
                        flag_meta_result = 1;
                    end
                end
                % 把求得的最好结果保存下来
                rx_all(:,(m-5).*32+(n-28),i) = [rx_meta_result;0;0];
                fval_all(1,(m-5).*32+(n-28),i) = fval_meta_result;
                flag_all(1,(m-5).*32+(n-28),i) = flag_meta_result;
                
            end
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 寻优结束,进行结果处理
% 在所有(K1、K2、K3、K4)求解结果中找目标函数最小的

% 判断(K1、K2、K3、K4)中哪一种的目标函数最小
ind_tmp = (flag_all >= 0);
if sum(sum(sum(ind_tmp))) ~= 0
    % K2、K3、K4的求解中找到了可行解(或最优解)
    val_tmp = fval_all.*ind_tmp;
    [val_tmp2,ind_tmp2] = min(val_tmp);
    [val_min,ind_tmp3] = min(val_tmp2);
    if (flag_k1 < 0)
        % K1的求解中没找到可行解
        signal = 1;     % 标志变量
    else
        if val_min < fval_k1
            signal = 1;
        elseif val_min > fval_k1
            signal = 2;
        else
            signal = 3;
        end
    end
    ;
else
    % K2、K3、K4的求解中没有找到了可行解
    if (flag_k1 < 0)
        % K1的求解中没找到可行解
        disp('(K1、K2、K3、K4)所有的求解中')
        disp('一个可行解都没有找到')
        disp('(还并不意味着完全没有可行解,')
        disp('也许是初值点选的不好因此没有找到)')
        break;
    else
        signal = 2;
    end
end

if (signal == 1)
    ind_tmp4 = ind_tmp2(ind_tmp3);
    rx_result = rx_all(:,ind_tmp4,ind_tmp3);
    fval_result = fval_all(:,ind_tmp4,ind_tmp3);
    fval_result =-fval_result;
    n = (ind_tmp4 - floor(ind_tmp4 / 32) * 32) + 28;
    m = floor(ind_tmp4 / 32) + 5;
    p_tmp = p_all(:,ind_tmp4,ind_tmp3);
elseif signal == 2
    rx_result = rx_k1;
    fval_result =-fval_k1;
    p_tmp = p_k1;
else    %signal == 3
    ind_tmp4 = ind_tmp2(ind_tmp3);
    rx_result = rx_all(:,ind_tmp4,ind_tmp3);
    fval_result = fval_all(:,ind_tmp4,ind_tmp3);
    fval_result =-fval_result;
    n = (ind_tmp4 - floor(ind_tmp4 / 32) * 32) + 28;
    m = floor(ind_tmp4 / 32) + 5;
end

% 输出计算结果
if signal == 1      % 最优解在K2、K3、K4中时
    if ind_tmp3 == 1
        disp(sprintf('最优解为:K2型,%d选%d',n,m));
    elseif ind_tmp3 == 2
        disp(sprintf('最优解为:K3型,%d选%d+1',n,m));
    elseif ind_tmp3 == 3
        disp(sprintf('最优解为:K4型,%d选%d无特别号',n,m));
    end
elseif signal == 2  % 最优解在K1中时
    disp(sprintf('最优解为:K1型,10选6+1'));
else                % K1的解和K2、K3、K4的解重合时
    if ind_tmp3 == 1
        disp(sprintf('10选6+1和K2型%d选%d同为最优解',n,m));
    elseif ind_tmp3 == 2
        disp(sprintf('10选6+1和K3型%d选%d+1同为最优解',n,m));
    elseif ind_tmp3 == 3
        disp(sprintf('10选6+1和K4型%d选%d无特别号同为最优解',n,m));
    end
end
disp('对应的目标函数值为:')
disp(fval_result)
if signal ~= 3
    disp('最终求解变量值为:')
    disp(rx_result)
    disp('各奖项的金额是:')
    x=zeros(3,1);
    x(1) = (1-p_tmp(4).*rx_result(4)-...
              p_tmp(5).*rx_result(5)-...
              p_tmp(6).*rx_result(6)-...
              p_tmp(7).*rx_result(7)).*rx_result(1)./p_tmp(1);
    x(2) = (1-p_tmp(4).*rx_result(4)-...
              p_tmp(5).*rx_result(5)-...
              p_tmp(6).*rx_result(6)-...
              p_tmp(7).*rx_result(7)).*rx_result(2)./p_tmp(2);
    x(3) = (1-p_tmp(4).*rx_result(4)-...
              p_tmp(5).*rx_result(5)-...
              p_tmp(6).*rx_result(6)-...
              p_tmp(7).*rx_result(7)).*rx_result(3)./p_tmp(3);
    rx_money=[x;rx_result(4:7)];
    disp(rx_money)
else
    disp('最终求解变量值为:')
    disp('10选6+1时')
    disp(rx_k1)
    disp('K%d型时',ind_tmp3+1)
    disp(rx_result)
end