精华内容
下载资源
问答
  • 在某些场合,我们可能会期待 a / b 返回浮点型,可是由于某些不确定的因素,参与运算的 a 和 b都是整型,这可能会带来错误,显然有精度上的损失。 v2.2 以后,引入了“地板除”(“//”)运算符,从数值上讲,...
    v2.2 以前,除(“/”)运算符的返回有两种可能情况,分别是整型和浮点型。操作数的不同,是影响计算结果数据类型的关键。
    以 a / b 为例,a、b均为整型,则结果返回整型;a、b任意一个是浮点型的话,则结果就是浮点型。
    ===========================
    # python v2.7
    >>> 3 / 2, 3.0 / 2, 3.0 / 2.0
    (1, 1.5, 1.5)
    ===========================

    在某些场合,我们可能会期待 a / b 返回浮点型,可是由于某些不确定的因素,参与运算的 a 和 b都是整型,这可能会带来错误,显然有精度上的损失。

    v2.2 以后,引入了“地板除”(“//”)运算符,从数值上讲,它返回小于除法运算结果的最大整数;从类型上讲,与"/"运算符返回类型逻辑一致。
    而“/”运算符,没有变化。
    ===========================
    # python v2.7
    >>> 3 / 2, 3.0 / 2, 3 // 2, 3.0 // 2
    (1, 1.5, 1, 1.0)
    ===========================

    v3.x 以后,“/”运算符被命名为“真除”,不再依据操作数类型选择返回值类型,保证计算结果数值上的精度是第一位的。所以,无须再把操作数转变成浮点型,以保证运算结果不被截断小数部分。
    “//”运算符,不变。
    ===========================
    # python v3.2
    >>> 3 / 2, 3.0 / 2, 3 // 2, 3.0 // 2
    (1.5, 1.5, 1, 1.0)
    ===========================
    展开全文
  • 使用网络分析(ANP)解决车辆选择问题及其代码实现问题:补充知识: 1. 当判断矩阵具有完全一致性时,CI=0; 2. 当判断矩阵具有满意一致性时,需引入判断矩阵的平均随机一致性指标RI值。对于1-9阶判断矩阵,RI值如下...

    使用网络分析法(ANP)解决车辆选择问题及其代码实现

    问题:

    补充知识:
    1. 当判断矩阵具有完全一致性时,CI=0;
    2. 当判断矩阵具有满意一致性时,需引入判断矩阵的平均随机一致性指标RI值。对于1-9阶判断矩阵,RI值如下

    阶数阶数阶数阶数阶数阶数阶数阶数阶数
    123456789
    RI=000.580.901.121.241.321.411.45

    3. CR=CI/RI<0.10时,可以认为判断矩阵具有满意的一致性,否则需要调整判断矩阵
    4. 引入判断矩阵最大特征根以外的其余特征根的负平均值,作为度量判断矩阵偏离一致性的指标,即用:CI=(λmax-n)/(n-1)检查决策者思维的一致性。CI值越大,表明判断矩阵偏离完全一致性的程度越大;CI值越小(接近于0),表明判断矩阵的一致性越好。

    问题抽象如图所示:

    ques1.png

    解题过程:
    首先写出三种因素:成本、维修和耐用性对于三类车辆的判断矩阵,并求出特征向量与随机一致性比率CR
    ques2.png

    ques3.png

    ques4.png

    接着,再考虑成本、维修和耐用性之间的相互影响,得到三者的权重矩阵如下:(此权重矩阵题目中已明确给出)
    ques5.png

    得到初始超矩阵

    ques6.png

    假定A=[0.5,1;0.5,0],则加权超矩阵

    ques7.png

    将加权超矩阵稳定处理,即自乘4-6次,得到稳定的极限超矩阵。(注意,每一步自乘之前需要将列向量归一化,否则加权超矩阵会越变越小,不会收敛)

    ques8.png

    ANP决策结果表明:美国车是最优选择,成本是决定性因素。

    至此,题目结束。

    下面放上代码实现:

    clc
    clear
    close all
    
    %选车算例的解答
    %% 列出所有的判断矩阵
    %成本指标下美日欧三种车间的判断矩阵
    A1=[1,5,3;
      1/5,1,1/3;
      1/3,3,1];
    %维修指标下美日欧三种车间的判断矩阵
    A2=[1,5,2;
      1/5,1,1/3;
      1/2,3,1];
    %耐用性指标下美日欧三种车间的判断矩阵
    A3=[1,1/5,1/3;
      5,1,3;
      3,1/3,1];
    %美车三种指标下间的判断矩阵
    A4=[1,3,4;
      1/3,1,1;
      1/4,1,1];
    %欧车三种指标下间的判断矩阵
    A5=[1,1,1/2;
      1,1,1/2;
      2,2,1];
    %日车三种指标下间的判断矩阵
    A6=[1,2,1;
      1/2,1,1/2;
      1,2,1];
    
    %% 计算6个判断矩阵的特征向量
    %计6个判断矩阵的特征向量和CR
    [B1,D1]=eig(A1);
    [B2,D2]=eig(A2);
    [B3,D3]=eig(A3);
    [B4,D4]=eig(A4);
    %严格得说每个判断矩阵都需要判断是不是一致阵,如果是的话就不需要再求特征向量和特征根
    %即:(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
    %由于rank(A5)=rank(A6)=1是一致阵,故下面两步不再需要
    %[B5,D5]=eig(A5);
    %[B6,D6]=eig(A6);
    %这里作者是算出来答案跟结果不对才回去判断的一致阵,所以程序编得不是很严谨,从逻辑上来说是错误的。即看着结果推程序,所以很遗憾本程序对于解答的推广无积极意义。
    %希望读者自行修改程序,先判断是否是一致阵,再计算特征根特征向量
    %直接将各自的第一列设为特征向量
    B5=A5(1:3,1);
    B6=A6(1:3,1);
    
    %求λmax最大特征根
    lamdaMax1=max(max(D1));
    lamdaMax2=max(max(D2));
    lamdaMax3=max(max(D3));
    lamdaMax4=max(max(D4));
    %一致阵的最大特征根为阶数n
    lamdaMax5=length(A5);
    lamdaMax6=length(A6);
    
    n=length(A1);
    CI(1)=(lamdaMax1-n)/(n-1);
    CI(2)=(lamdaMax2-n)/(n-1);
    CI(3)=(lamdaMax3-n)/(n-1);
    CI(4)=(lamdaMax4-n)/(n-1);
    CI(5)=(lamdaMax5-n)/(n-1);
    CI(6)=(lamdaMax6-n)/(n-1);
    %CI=(λmax-n)/(n-1)
    %对1-9阶判断矩阵,RI值如下:(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
    %1   2   3     4    5    6    7   8    9
    %0   0  0.58 0.90 1.12 1.24 1.32 1.41 1.45
    %由于n=3故RI(3)=0.58
    RI=0.58;
    %判断矩阵的一致性指标CI与同阶平均随机一致性指标RI之比称为随机一致性比率CR,当CR=CI/RI<0.10时,可以认为判断矩阵具有满意的一致性,否则需要调整判断矩阵。
    %CR=CI/RI=0.0285/1.12=0.0255<0.10 因此,通过一致性检验。
    for i=1:6
        CR(i)=CI(i)/RI;
        if CR(i)<0.1
            disp(strcat('判断矩阵',num2str(i),'通过一致性检验'));
        else
            disp(strcat('判断矩阵',num2str(i),'未通过一致性检验'));
        end
    end
    (Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
    %权重即为最大特征根对应的特征向量W进行归一化后的结果,w=W./sum(W)
    W1=B1(1:n,1);
    w1=W1./sum(W1);
    
    W2=B2(1:n,1);
    w2=W2./sum(W2);
    
    W3=B3(1:n,1);
    w3=W3./sum(W3);
    
    W4=B4(1:n,1);
    w4=W4./sum(W4);
    
    W5=B5(1:n,1);
    w5=W5./sum(W5);
    
    (Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
    W6=B6(1:n,1);
    w6=W6./sum(W6);
    %% 输出阶段结果
    CR
    w1
    w2
    w3
    w4
    w5
    w6
    %% 计算极限超矩阵
    %再考虑成本、维修和耐用性之间的相互影响,得到三者的权重矩阵
    C=[0.3,0.2,0.6;
        0.4 0.25 0.3;
        0.3 0.55 0.1];
    %初始超矩阵
    %行列均为:成本 维修 耐用性 美 欧 日
    super=[C  w4 w5  w6
           w1 w2 w3 zeros(3)];
    %令归一化的排序向量A为[0.5,1;0.5,0],则加权超矩阵为[0.5*WW1 1*WW2;0.5*WW3 0*WW4]
    %A=[ones(6,3)*0.5 ones(6,3)];appears to be a bad example
    WW1=super(1:3,1:3);
    WW2=super(1:3,4:6);
    WW3=super(4:6,1:3);
    WW4=super(4:6,4:6);
    %powerSuper=A.*super;appears to be a bad example
    powerSuper=[0.5*WW1 1*WW2;0.5*WW3 0*WW4];
    ppowerSuper=powerSuper;
    for m= 1:6
        P1=ppowerSuper(1:6,1);
        P2=ppowerSuper(1:6,2);
        P3=ppowerSuper(1:6,3);
        P4=ppowerSuper(1:6,4);
        P5=ppowerSuper(1:6,5);
        P6=ppowerSuper(1:6,6);
        p1=P1./sum(P1);
        p2=P2./sum(P2);
        p3=P3./sum(P3);
        p4=P4./sum(P4);
        p5=P5./sum(P5);
        p6=P6./sum(P6);
        ppowerSuper=[p1,p2,p3,p4,p5,p6]^2;
    end
    %% 输出最终结果
    ppowerSuper

    最后算出的加权超矩阵与上方最后的示例答案有些许出入,但不严重。基本认定程序的可靠性。

    (Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)


    visitor tracker
    访客追踪插件


    展开全文
  • 算法系列之十六:使用穷举解猜结果游戏

    万次阅读 热门讨论 2012-05-27 23:01:37
    采用穷举的方法求解问题的答案比较适合计算机做,对这种体力活它们没有怨言,本文就以常见的两个猜结果的题目为例,介绍一下如何通过计算机程序解决此类问题,顺便介绍一下穷举常见的算法结构和实现方式。

    一、 引言

             穷举是解决问题的一种常用思路,当对一个问题无从下手的时候,可以考虑在问题域允许的范围内将所有可能的结果穷举出来,然后根据正确结果的判断规则对这些结果逐个验证,从而找出正确的结果。采用穷举的方法求解问题的答案比较适合计算机做,对这种体力活它们没有怨言,本文就以常见的两个猜结果的题目为例,介绍一下如何通过计算机程序解决此类问题,顺便介绍一下穷举法常见的算法结构和实现方式。

     

     二、 猜结果游戏的分析过程

             先来看一个问题,有五个运动员(甲、乙、丙、丁、戊)参加运动会,分别获得了一百米、二百米、跳高、跳远和铅球冠军,现在有另外四个人(ABCD)对比赛的结果进行了描述,分别是:

    A说:“乙获得铅球冠军,丁获得跳高冠军”

    B说:“甲获得一百米冠军,戊获得跳远冠军”

    C说:“丙获得跳远冠军,丁获得二百米冠军”

    D说:“乙获得跳高冠军,戊获得铅球冠军”

    ABCD四个人每个人的描述都对一句,错一句,现在根据这四个人的描述猜一下五名运动员各获得了什么项目的冠军?

     

            现在来分析这个问题,五个运动员获得5个冠军,正确的结果需要5个描述即可,现在题目给出了四个人的8个描述,其中一些是相互矛盾的错误描述,因此需要对这些描述的正确性进行假设,假设的过程其实就是穷举的过程。每个人有两个描述,分别对其进行正确性假设可以得到两个假设结果,四个人就有2416种假设结果的组合,下表就是这16种假设结果组合的全部描述:

            描述

    结果

    A

    B

    C

    D

    1

    对,错

    对,错

    对,错

    对,错

    2

    对,错

    对,错

    对,错

    错,对

    3

    对,错

    对,错

    错,对

    对,错

    4

    对,错

    对,错

    错,对

    错,对

    5

    对,错

    错,对

    对,错

    对,错

    6

    对,错

    错,对

    对,错

    错,对

    7

    对,错

    错,对

    错,对

    对,错

    8

    对,错

    错,对

    错,对

    错,对

    9

    错,对

    对,错

    对,错

    对,错

    10

    错,对

    对,错

    对,错

    错,对

    11

    错,对

    对,错

    错,对

    对,错

    12

    错,对

    对,错

    错,对

    错,对

    13

    错,对

    错,对

    对,错

    对,错

    14

    错,对

    错,对

    对,错

    错,对

    15

    错,对

    错,对

    错,对

    对,错

    16

    错,对

    错,对

    错,对

    错,对

     

    寻找正确答案的过程就是对这16组假设结果逐个判断的过程。先来看看第1个结果,A说“乙获得铅球冠军”被假定是正确的,但是D说“乙获得跳高冠军”也被假定是正确的,因为一个运动员只能获得一个冠军,因此第1个结果就互相矛盾,不能得到正确的答案。再来看看第2个结果,A说“乙获得铅球冠军”被假定是正确的,但是D说“戊获得铅球冠军”也被假定是正确结果,这又是另一种矛盾,因为铅球冠军不能被两个人同时获得。如果某个结果的所有假定没有互相矛盾的地方,就可以得到一个正确的结果,比如第10个结果,其正确的描述分别是A的第二句描述、BC的第一句描述以及D的第二句描述,这几个描述没有矛盾,可以得到一个正确答案,就是:

     

    丁获得跳高冠军   A描述的第二句)

    甲获得一百米冠军(B描述的第一句)

    丙获得跳远冠军   C描述的第一句)

    戊获得铅球冠军   D描述的第二句)

    乙获得二百米冠军  (根据前面的结果做不矛盾推解)

     

    三、 用程序求解猜结果游戏

     

     3.1 建立数学模型

            《算法系列》的文章中多次提到,为计算机程序建立的数学模型必须能够解决三大问题,其一是要能够方便地把自然语言描述的问题转化成计算机能够理解的数据结构,其二是转换后的数据结构要适用与问题的求解模式并能够推演出正确的结果,其三是能够方便地把求解的结果转化成自然语言方式的输出。针对不同的问题建立的数学模型没有统一的模式,也没有标准答案,能够解决问题就是正确的数学模型,但是只有简洁且能够配合算法高效地求解问题的数学模型才是好的数学模型。

            首先需要数学模型化的是四个人的描述,考察这些自然语言的描述,发现每句描述其实只包含了两个信息:一个是运动员是谁?另一个是他得了什么冠军?如果我们给每个运动员编一个序号,同时给每种运动的冠军也编一个序号,则每个自然语言的描述就可以量化为两个数字。为运动员或冠军编制序号有多种方法,本文的算法采用的是C/C++语言,因此用枚举类型来定义它们:

    13 typedef enum tagAthleteNumber

    14 {

    15     athleteJia = 0,

    16     athleteYi,

    17     athleteBing,

    18     athleteDing,

    19     athleteWu

    20 }AthleteNumber;

    21 

    22 typedef enum tagChampionResult

    23 {

    24     ShotChampion = 0,

    25     HighJumpChampion,

    26     LongJumpChampion,

    27     OneHMChampion,

    28     TwoHMChampion

    29 }ChampionResult;

     描述的数学模型就可以这样定义:

    32 typedef struct tagDescription

    33 {

    34     AthleteNumber athlete;

    35     ChampionResult result;

    36 }Description;

    最终自然语言描述的问题就可以量化为如下二维数组:

    44 Description peopleDesc[peopleCount][descPerPeople] =

    45 {

    46     { {athleteYi, ShotChampion}, {athleteDing, HighJumpChampion} },

    47     { {athleteJia, OneHMChampion}, {athleteWu, LongJumpChampion} },

    48     { {athleteBing, LongJumpChampion}, {athleteDing, TwoHMChampion} },

    49     { {athleteYi, HighJumpChampion}, {athleteWu, ShotChampion} }

    50 };

            问题的求解过程中,还有一个重要信息需要记录,那就是每一个描述者提供的两个描述中总是一真一假。穷举的过程就是真和假的不断假设过程,根据第二节的分析,在这个过程中可以得到16组真和假的配对结果,这也需要一个数学模型承载这些配对结果。本来描述是四个人给出的,每个人给出两个描述,但是结果判断不需要知道某个描述是哪个人给出的,只需要知道描述的内容以及结果认定是真还是假就可以了,因此定义每组配对结果为一维数组,从而简化算法:

     std::vector<DescDecision> decisions;

     DescDecision定义包含两部分,一部分是描述Description,另一部分是描述真假标志,具体定义如下:

    38 typedef struct tagDescDecision

    39 {

    40     Description desc;

    41     bool decision;

    42 }DescDecision;

    最后是结果输出,通过对问题的分析可以得知,结果其实就是5个描述,只不过这5个描述都是正确的,因此结果也可以定义为Description的数组:

     std::vector<Description> result;

    3.2 正确结果判断方法

             穷举可以得到问题域内的所有可能的结果,但是如何判断哪个是正确的结果?根据本题的题意,正确的结果就是所有描述都没有互相矛盾的结果。再根据第二节的分析,这个题目只有两种可能的矛盾:一种是两个运动员得到同一个冠军,另一种是同一个运动员得到两个(或两个以上)冠军。

            正确结果的判断和结果的生成是同时进行的,对每个穷举得到的结果开始判断之前,result是空的。每个穷举结果有8个描述,逐个进行判断,当一个描述被标识为正确描述,且和result中的现有描述不矛盾,则将这个描述加入到result中,如果一个描述被判定与result中已经的描述有矛盾,则说明这个结果中的8个描述有互相矛盾的地方,无法得到正确结果,直接返回错误。当某个穷举结果的8个描述全部判断完成,没有返回错误,则说明得到了一个正确的结果。ParseResultFromDecisions()函数就是完成上述过程:

    119 bool ParseResultFromDecisions(const std::vector<DescDecision>& decisions,

    120                               std::vector<Description>& result)

    121 {

    122     std::vector<DescDecision>::const_iterator cit;

    123     for(cit = decisions.begin(); cit != decisions.end(); ++cit)

    124     {

    125         if(CheckDecision(result, *cit))

    126         {

    127             if(cit->decision)//如果是不矛盾的真描述,就记录结果

    128             {

    129                 result.push_back(cit->desc);

    130             }

    131         }

    132         else

    133         {

    134             return false;

    135         }

    136     }

    137 

    138     //只有四个描述,需要补上第五个描述,且不能矛盾

    139     PatchTheLastOne(result);

    140     return true;

    141 }

    CheckDecision()函数就是判断当前的描述是否与result中已有的描述(被认定是正确的描述)冲突,主要方法就是逐项检查result中的描述,判断其是否与当前描述存在两类矛盾的情况,实现方法如下:

     70 bool CheckDecision(const std::vector<Description>& result, const DescDecision& decision)

     71 {

     72     std::vector<Description>::const_iterator cit;

     73     for(cit = result.begin(); cit != result.end(); ++cit)

     74     {

     75         if(cit->athlete == decision.desc.athlete)

     76         {

     77             if(decision.decision && (decision.desc.result != cit->result))

     78             {

     79                 return false;

     80             }

     81             if(!decision.decision && (decision.desc.result == cit->result))

     82             {

     83                 return false;

     84             }

     85         }

     86         if(cit->result == decision.desc.result)

     87         {

     88             if(decision.decision && (decision.desc.athlete != cit->athlete))

     89             {

     90                 return false;

     91             }

     92             if(!decision.decision && (decision.desc.athlete == cit->athlete))

     93             {

     94                 return false;

     95             }

     96         }

     97     }

     98 

     99     return true;

    100 }

    最后说明一下PatchTheLastOne()函数的作用,对于一个完整的正确答案,应该是5个描述,但是四个人的描述只有4个正确描述,在互相不矛盾的基础上,需要补上第5个描述,PatchTheLastOne()函数就是做这个事情。补的方法很简单,就是前4个描述中没有提到的那个运动员得到的是前4个描述中没有提到的那个项目的冠军。因为简单,这里就不列出代码了。

     

    3.3 穷举算法

             猜结果游戏的穷举算法与排列组合算法类似,或者说就是使用排列组合的穷举方式。《算法系列》的《排列组合算法》一文对常见的排列组合算法都有介绍,这里不再赘述。只是在选择多重循环还是递归方法上,我倾向于使用递归方法,原因就是代码简单易懂。本算法穷举的主要思想就是对四个描述者的真假状态逐个进行遍历,使用递归结构,每次遍历一个人的描述。用一个索引来标识当前要遍历真假状态的描述者,当索引达到最大值时,表示一组描述结果完成,可以尝试判断是否此结果就是正确结果。以下就是递归方式的穷举算法主体部分代码:

    159 void EnumPeopleDescriptions(int peopleIdx,

    160                             std::vector<DescDecision>& decisions,

    161                             void (*callback)(const std::vector<DescDecision>& decisions))

    162 {

    163     if(peopleIdx == peopleCount)

    164     {

    165         callback(decisions);

    166         return;

    167     }

    168 

    169     EnumPeopleDescriptions(peopleIdx + 1, decisions, callback);

    170     //翻转描述者两个描述的状态,总是保持一对一错

    171     DescDecision& dd1 = decisions[peopleIdx * descPerPeople];

    172     dd1.decision = !dd1.decision;

    173     DescDecision& dd2 = decisions[peopleIdx * descPerPeople + 1];

    174     dd2.decision = !dd2.decision;

    175     EnumPeopleDescriptions(peopleIdx + 1, decisions, callback);

    176 }

    peopleIdx参数就是描述者索引,decisions参数就是当前对所有描述的真假判断结果,通过成对地翻转一个描述者的两个描述的真假状态,达到枚举所有结果的目的。callback回调函数负责判断一组结果是否正确并打印正确的结果,DescriptionsCallback()函数就是本算法使用的callback回调函数:

    148 void DescriptionsCallback(const std::vector<DescDecision>& decisions)

    149 {

    150     std::vector<Description> result;

    151 

    152     if(ParseResultFromDecisions(decisions, result))

    153     {

    154         PrintResult(result);

    155     }

    156 }

    ParseResultFromDecisions()函数在3.2节已经介绍过了,PrintResult()函数只是用来输出正确结果,无需多做说明。

     

    3.4 结果输出

             至此,完整的算法都已经介绍完毕,剩下的就是输出结果,结果不出意外,只有一个正确答案:

     丁获得跳高冠军

    甲获得一百米冠军

    丙获得跳远冠军

    戊获得铅球冠军

    乙获得二百米冠军

     

    这个输出是按照描述者的正确描述顺序输出的,不太符合生活习惯,调整其实也很简单,只要在结果输出前进行一次排序即可:

     sort(result.begin(), result.end(), AthleteComparator);

     AthleteComparator()函数比较运动员编号大小,排序后的输出就是这个样子了:

     甲获得一百米冠军

    乙获得二百米冠军

    丙获得跳远冠军

    丁获得跳高冠军

    戊获得铅球冠军

     

    3.5 另一个猜结果游戏

             此类型的猜结果游戏很多,参照上面的代码,稍加修改就可以解决类似的问题,比如这个猜结果游戏:

     

    有五个游泳运动员参加完比赛回来时有人询问他们的比赛结果,他们说“我们每个人都告诉你两个结果,其中一个正确,一个错误,你自己猜猜名次究竟如何?”

    甲说:“乙第二,我第三”

    乙说:“我第二,戊第四”

    丙说:“我第一,丁第二”

    丁说:“丙最后,我第三”

    戊说:“我第四,甲第一”

    名次究竟如何,你猜出来了吗?

     

    这个题目的描述者就是运动员本身,与前面讨论的题目有些差异,但是本文介绍的算法并不关心描述者信息,只关心其描述的内容,因此前面的算法也适用于这个题目,只需把描述中标识自己的第一人称“我”修改成相应的描述者就可以了,修改后的描述就变成和描述者无关的信息了:

     

    甲说:“乙第二,第三”

    乙说:“第二,戊第四”

    丙说:“第一,丁第二”

    丁说:“丙最后,第三”(丙最后,其实就是丙第五)

    戊说:“第四,甲第一”

     

    根据描述内容修改描述的定义如下:

    32 typedef struct tagDescription

    33 {

    34     AthleteNumber athlete;

    35     MatchResult result;

    36 }Description;

    其中有改变的是MatchResult,定义如下:

    22 typedef enum tagMatchResult

    23 {

    24     matchNo1 = 0,

    25     matchNo2,

    26     matchNo3,

    27     matchNo4,

    28     matchNo5

    29 }MatchResult;

    最后把输出结果的函数稍作调整,整体代码无需做修改就可以得到结果了,有两组与描述都不冲突的结果,第一组结果是:

     

    甲获得第五名

    乙获得第二名

    丙获得第一名

    丁获得第三名

    戊获得第四名

     

    第二组结果是:

     

    甲获得第三名

    乙获得第一名

    丙获得第五名

    丁获得第二名

    戊获得第四名

     

    四、 总结

             穷举类方法的重点就是两个,一个是穷举所有可能解的方法,另一个是判断正确解的规则。前一个重点需要一些技巧来构造合适的穷举算法,对于不同的问题来说,穷举算法的差异很大,没有统一的模板可以借用。后一个判断正确解的规则可以根据题目自然语言的描述构造,也没有定势可用。当然,这两者都是需要建立在适当的数学模型上的,明智地构造数学模型可以简化算法的复杂度,提高效率,对于一个成功的算法来说,以上都是缺一不可的。

     

    展开全文
  • 一、试探回溯(N皇后问题)

    千次阅读 2018-11-26 16:17:23
    一、试探回溯概念 在介绍试探回溯的概念之前,先简要介绍一个简短的古希腊神话故事,邪恶的...其实,忒修斯使用的法宝很简单,就是一团普通的绳,他将绳子的一段在迷宫的入口上,然后用手拿着另一端进入迷宫...

     一、试探回溯法概念

    在介绍试探回溯法的概念之前,先简要介绍一个简短的古希腊神话故事,邪恶的半人半牛藏身于一个复杂的迷宫,很难找到它并杀死它,就是能成功杀死它怎么回来也是个难事。不过,在公主阿里阿德涅的帮助下,英雄忒修斯还是想到办法并消灭了怪物,并轻轻松松地走出了迷宫,他是怎么做到的呢?

    其实,忒修斯使用的法宝很简单,就是一团普通的绳,他将绳子的一段系在迷宫的入口上,然后用手拿着另一端进入迷宫,在此后不断检查各个角落的过程中,线团或收或放,跟随着他辗转于曲折的迷宫中,确保它不会迷路。此外,为保证搜索过的角落不会重复,忒修斯在他已经检查过的而且确保不会有怪物的地方用粉笔做好记号,下次不会再去。

    故事讲完了,古希腊神话故事中往往蕴含着很多哲理,这个故事也不例外,其实忒修斯的高招,与现代计算机中求解一些问题的试探回溯算法异曲同工,其中忒修斯探索未知角落就是试探,而发现该角落是错误的的并留下记号返回,这个过程是回溯,也可以叫做剪枝

    试探:从长度上逐步向目标解靠近的尝试。

    回溯(剪枝):做为解的局部特征,特征前缀在试探的过程中一旦被发现与目标解不合,则收缩到此前一步的长度,然后继续试探下一可能的组合。

    应用:试探回溯法可解决若干元素为达到某种结果的最优排序方式问题,如N皇后问题和迷宫问题。

    二、N皇后问题

    世界历史上曾经出现一个伟大的罗马共和时期,处于权力平衡的目的,当时的政治理论家波利比奥斯指出:“事涉每个人的权利,绝不应该让任何权利大的压过其它力量,使他人无法立足于平等条件与之抗辩的地步。”这类似著名的N皇后问题,即在NXN格的国际象棋上摆放N个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,请问有多少中摆法,并将每种摆法打印出来。图1所示即是摆法的一种。

    对于N皇后问题,若采用普通穷举算法,则所有可能为n!=O(n^n)的复杂度,让人难以接受,故采用试探回溯法,可以尽早地发现不可能的情况进行回溯(剪枝),从而大大提高求解效率。

    思路:N个皇后,N*N的方阵,已知queen不能同行,那么每行肯定都有一个皇后,那么问题转变成求N个y在满足皇后问题这一条件下的所有排序可能。

    (1) 首先构造描述queen的类,其中重要的是判断queen之前是否冲突的==运算符。

    #pragma once
    
    class queen
    {
    public:
    	//皇后的坐标(x,y)
    	int x, y;
    
    	//构造函数
    	queen(int xx = 0, int yy = 0) :x(xx), y(yy) {}
    	//析构函数
    	~queen(){}
    
    	//成员函数
    	bool operator==(const queen& q) const  //重载判等运算符,判断皇后间是否冲突(同行、同列、正对角、反对角)
    	{
    		if (x == q.x || y == q.y) return true;    //同行或者同列
    		if ((x - q.x) == (y - q.y)) return true;  //正对角
    		if((x-q.x)==(q.y-y)) return true;         //反对角
    		return false;
    	}
    	bool operator!=(const queen& q) const
    	{
    		return !(this->operator==(q));
    	}
    };

    (2) 求解算法

    int placeQueen(int N)    //试探回溯法解决N皇后问题
    {
    	stack<queen> solu;   //缓存当前解的路径                                y
    	queen q(0, 0);       //第一个queen放在(0,0)
    	int nSolu = 0;
    
    	while (q.x >= 0)     //如果没尝试完所有情况则继续(迭代的最后会一直回溯到空)
    	{
    		while ((solu.size() < N))  //未形成全解,则继续
    		{
    			while ((q.y < N) && (solu.find(q)))   //横向遍历y的所有可能(当y没出界且当前queen的试探位置和已放置的queen冲突)
    			{
    				q.y++;
    			}//横向遍历(y)结束
    			if (q.y < N) //未出界则试探成功
    			{
    				solu.push(q);   //生长当前解
    				q.x++;			//继续下一行(一行一个queen)
    				q.y = 0;
    			}
    			else //出界,则上一个queen的位置导致无解,回溯(剪枝)
    			{
    				if (solu.empty())  //已经无试探点可弹,则确认问题无解
    				{
    					q.x = -1;
    					cout << "======所有情况遍历完毕======" << endl;
    					break;
    				}
    
    				q = solu.pop();   //尝试上个无解试探点的下一列
    				q.y++;
    			}
    		}
    		//出解
    		if (solu.size() < N)
    			cout << "无其他解" << endl;
    		else
    		{
    			nSolu++;
    			cout << "第" << nSolu << "个解: " << endl;
    			q = solu.pop();   //返回上层继续寻找
    			q.y++;
    		}
    
    	}
    	return nSolu;
    }

     

    展开全文
  • Arcgis JS 坐标转换错误的解决方法

    千次阅读 2018-12-03 14:34:55
    Arcgis JS 开发时候报错 (wkid:***)arcgis cannot be converted to spatial reference of the map(wkid:***)... 这种写法导致了标题所示的错误,其实,只要修改了就好: new SpatialReference({wkid: 4490})
  • 目前在做一个学校的项目,正在tomcat上测试通过访问域名跳转页面。...java.net.BindException异常,因为address already in use:bind错误   百度之后,发现应该是tomcat端口被占用的问题。因为之前使用8080...
  • SAP错误问题汇总

    万次阅读 2016-07-18 10:16:58
    SAP错误问题汇总 1.A:在公司代码分配折旧表时报错? 在公司代码分配折旧表时报错,提示是“3000 的公司代码分录不完全-参见长文本” 希望各位大侠帮我看看。 3000 的公司代码分录不完全-参见长文本 R: a.你把...
  • 一、起因最近在玩Boost库。当然首先是要进行Booist...当进行到第五步,要在VS命令提示符中运行bootstrap.bat的时候,问题就来了,按着攻略打开Visual Studio2010命令提示符,就迎面报错:“Setting environment for usi
  • SPSS系列----异方差检验(等级相关系数检验

    万次阅读 多人点赞 2020-04-27 14:04:29
    这里写目录标题SPSS的异方差检验(等级相关系数检验)数据来源普通最小二乘法求回归方程功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的...
  • 究其原因,除了算法效率问题之外,还存在一个光栅图形设备和矢量之间的转换问题。比如某个点位于非常靠近边界的临界位置,用矢量算法判断这个点应该是在多边形内,但是光栅化后,这个点在光栅图形设备上看就有可能是...
  • 通过BigDecimal的divide方法进行除时当不整除,出现无限循环小数时,就会抛异常的: java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result 解决方法:...
  • 声明:版权所有,转载请联系作者并注明... 用字典学习分解分类 在这个主题中,我们将介绍一种可以用于分类的分解方法——字典学习(Dictionary Learning),将数据集转换成一个稀疏的形式。 Getti
  • Air系列模块常见问题列表

    万次阅读 2021-04-26 15:24:42
    目录名称一、Luatools使用问题1.1 烧录下载  1.1.1、 2G模块无法烧录下载  1.1.2、 2G开发板无法烧录下载  1.1.3、4G模块(开发板)无法烧录下载  1.1.4、生成量产文件时的加密功能有什么用  1.1.5、4G开发模式...
  • 3.4 比较k折交叉验证与留一。本题采用UCI中的 Iris Data Set 和 Blood Transfusion Service Center Data Set,基于sklearn完成。
  • 从(http://blog.csdn.net/yexinghai/article/details/4649923)等其他网站上比较发现快速排序时间效率很高,从(http://www.cnblogs.com/luchen927/archive/2012/02/29/2368070.html)等网站中参考并改写了适合...
  • 此专栏文章是对力扣上算法题目各种方法的总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式...关于本专栏所有题目的目录链接, 刷算法题目的顺序/注意点/技巧, 以及思维导图源文件问题请点击此链接. 想进大厂.
  • 换元中,换元必须保证所换的新元是原来旧元的单调函数 原理: 用t代换一个x的函数f(x),t=f(x) 在运算过程中你会把x用t表示出来,相当于求f(x)的反函数 函数有反函数就要求函数是单调函数,故换元必须保证单调...
  • 10分钟看明白大M和两阶段

    千次阅读 多人点赞 2020-10-16 14:49:04
    相信学习本章节的朋友都是掌握了单纯形后,准备...在运用单纯性解题时,我们通常会苦恼于其繁琐的过程----换基迭代,一个不小心就会计算错误,但是除了这个问题以外,我们在还没有进行画表,即进行选择基向量时也有
  • 原因用etl工具kettle 从mongdb抽取一张表数据到db2时,报错 错误日志 里面见-4229错误
  • SAP错误问题汇总(转)

    千次阅读 2013-11-27 10:53:50
    1.A:在公司代码分配折旧表时报错?  在公司代码分配折旧表时报错,提示是“3000 的公司代码分录不完全-参见长文本” 希望各位大侠帮我看看。...据此可能company code 设置有问题,检查一下OBY6 2.a,维护客户科目
  • 这种错误据我所知一般发生在win10系统,因为win10系统的文件后缀名一般是隐藏的,像历代的win那样直接重命名是不好使的(当然也可以,但具体怎么改自己百度)这个问题比较好的解决方案是(举个例子)创建了一个...
  • BAT机器学习面试1000题系列

    万次阅读 多人点赞 2017-12-14 15:19:15
    2、文章中带斜体的文字代表是本人自己增加的内容,如有错误还请批评指正; 3、原文中有部分链接已经失效,故而本人重新加上了新的链接,如有不当,还请指正。(也已用斜体标出) 4、部分答案由于完全是摘抄自其它...
  • OpenGL: 编程低级错误 + 常见问题解答

    千次阅读 2014-04-15 15:43:06
    物体位置数据错误,导致物体大大超出镜头显示范围.4.纹理没有GL_CLAMP导致边界拼接出现缝线.5.纹理没有GL_REPEAT导致使用超出1.0纹理坐标技巧失败,显示单色插值.6.没有glEnable(GL_TEXTURE_2D)导致全白纹理.7....
  • 复数与相量

    千次阅读 多人点赞 2018-09-05 16:49:13
    实部、虚部(直角坐标): (a是实部,b是虚部) 幅值、相角(指数形式): (r是幅值,θ 是相角 ) 两种形式相互转换: 【证明】 若 ,则 所以 ,实部 ,虚部 幅值 ,相角 极坐标表示: 一个非...
  • python张正友相机标定的实现

    千次阅读 2019-04-13 21:16:50
    背景 我们拍摄的物体都处于三维世界坐标中,而相机拍摄时镜头看到的是三维相机坐标,成像时三维相机坐标向二维图像坐标转换。...对于张正友棋盘标定的详解可以参考:python-OpenCV Tutorial。 ...
  • PADS 原理图/PCB常见错误及DRC报告网络问题 http://csuhuadong.blog.163.com/blog/static/215827482009101814310843/ 1.原理图常见错误:  (1)ERC报告管脚没有接入信号:  a. 创建封装时给...
  • 数学笔记9——牛顿迭代

    万次阅读 多人点赞 2017-09-25 18:22:21
    牛顿迭代(Newton's method)又称为牛顿-拉夫逊(拉弗森)方法(Newton-Raphson method),它是牛顿在17世纪提出的一种在实数... 问题可以看作解方程x2=5,下面尝试用牛顿迭代求解。  首先令f(x)= x2 – 5 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 75,285
精华内容 30,114
关键字:

关于法系问题错误的是