現實生活中存在不少問題,好比商品買賣如何實現商家利潤最大化?大學生招生錄取如何實現總體效果最好?病人醫生如何實現總體服務水平最高等?這些咱們均可以把他統一的轉化爲雙邊決策問題。下面先說說本身對雙邊決策的理解。html
雙邊決策——我的理解java
爲了幫助你們理解,我用一個簡單的例子介紹什麼是雙邊決策,加入如今市場上有10位顧客,分別爲A0、A一、A二、A三、A四、A五、A六、A七、A八、A9,市場上有是個商品,分別爲B0、B一、B二、B三、B四、B五、B六、B七、B八、B9,如今要求要把這10個商品分別分給這10位顧客,要求總體的滿意程度最高,固然每位顧客對每一個商品的打分是不同的,加入M位顧客對N件商品的滿意度爲AMBN,那麼如何分配這些商品才能使總體的滿意度最高?像這個爲題就是一個雙邊決策問題。算法
算法介紹數組
目前關於雙邊決策的實現算法有不少,下面就介紹一種本身想到的(若有雷同,純屬巧合),這個算法是基於以前本身寫的一篇遺傳算法的文章想到的。本身這個算法要求顧客和商品的數目必須一致,而且是一對一的關係,若是數目不一致或者是一對N(N是一個具體值)的時候,咱們能夠經過構建虛擬的商品(顧客)來使用這個算法,下面我就簡單介紹下算法思想:app
1)咱們首先選取一個分配方案,這裏咱們不防假定初始的分配方案就是M件商品分給M位顧客;ide
2)咱們將比較步長step設置爲1;測試
3)判斷step是否超過數組長度,若是超過結束算法,若是沒超過繼續執行下一步;this
4)比較step步長下的兩位顧客,假設將他們的分配方案對調,若是對調以後的滿意度大於對調前的滿意度就進行對調,不然保持原樣,將比較位日後移動一位繼續進行第4)步;spa
5)該步長step下已經沒有能夠對調的分配方案,將步長step加1;.net
6)跳到第3)步繼續執行。
在上述算法描述中,咱們重點介紹下第4)步,這裏咱們假設第1位顧客分配的商品是1號商品,第2位顧客分配的商品是2號商品,他們對商品的滿意度分別爲A1B一、A2B2,這時這兩個顧客的整體滿意度爲SCORE1=A1B1+A2B2,這裏咱們將他們的分配方案對調,也就是第1位顧客分配的商品是2號商品,第2位顧客分配的商品是1號商品,這時候他們對商品的滿意度分別爲A1B二、A2B1,這兩個顧客的總體滿意度爲SCORE2=A1B2+A2B1,若是SCORE1小於SCORE2,那麼咱們就改變分配策略,不然保持原來的分配策略。
Java代碼分析
對於上面的介紹也許並非太具體,或者並不知道用JAVA如何實現,下面咱們就對如何實現作拆解:
1)在寫算法的時候,咱們首先須要定義一些常量、保存分配方案等:
[java] view plain copy
print?
- public class TwoSidedDecision {
- private int num = 10;//個體數目
- private boolean maxFlag = true;//是否求最大值
- private int[][] scoreArray;//AB之間的互評得分
- private int[] decisionArray;//A選擇B的方式
- }
這裏有一個maxFlag屬性,他的做用是用來標識咱們的雙邊決策是要取最大值仍是要取最小值,true表示最大值,false表示最小值;num用來標識個體的個數,scoreArray數組用來表示用戶對商品的滿意度,decisionArray用來保存商品的分配方案,decisionArray[0]表示編號爲0的顧客分配的商品是decisionArray[0];
2)在運行算法以前,咱們須要設置個體數目
[java] view plain copy
print?
- public void setNum(int num) {
- if (num < 1) {
- System.out.println("num must be greater than 0");
- return;
- }
- this.num = num;
- }
3)顧客對商品進行滿意度打分並肯定初始分配方案
[java] view plain copy
print?
- public void setScoreArray(int[][] scoreArray) {
- if (scoreArray == null) {
- System.out.println("scoreArray is null");
- }
- if (!(scoreArray.length == num && scoreArray[0].length == num)) {
- System.out.println("scoreArray`s must be " + num);
- }
- this.scoreArray = scoreArray;
- decisionArray = new int[num];
- //初始決策,對角線
- for (int i = 0; i < num; i++) {
- decisionArray[i] = i;
- }
- decision();
- }
4)而後進行算法描述中的第4)步,確認分配方案是否對調
[java] view plain copy
print?
- private boolean compare(int stepSize) {
- for (int i = 0; i < num - stepSize; i++) {
- int a1 = i;
- int a2 = i + stepSize;
- int b1 = decisionArray[a1];
- int b2 = decisionArray[a2];
- //原始兩個得分之和
- int score1 = scoreArray[a1][b1] + scoreArray[a2][b2];
- int between1 = Math.abs(scoreArray[a1][b1] - scoreArray[a2][b2]);
- //交換後的兩個得分之和
- int score2 = scoreArray[a1][b2] + scoreArray[a2][b1];
- int between2 = Math.abs(scoreArray[a1][b2] - scoreArray[a2][b1]);
- if (maxFlag) { //最後的得分最大
- if (score1 <= score2) {//交換後的分數不小於交換前的
- //交換後的分數大於交換前的或者交換後的差值大於交換前的
- if (score1 < score2 || between2 > between1) {
- decisionArray[a1] = b2;
- decisionArray[a2] = b1;
- return true;
- }
- }
- } else { //最後的得分最小
- if (score1 >= score2) {//交換後的分數不小於交換前的
- //交換後的分數大於交換前的或者交換後的差值大於交換前的
- if (score1 > score2 || between2 > between1) {
- decisionArray[a1] = b2;
- decisionArray[a2] = b1;
- return true;
- }
- }
- }
- }
- return false;
- }
這個方法的返回值是確認該步長下是否發生對調,若是該步長沒有發生對調,咱們能夠進行下一個步長的比較。這樣就完成了雙邊決策算法,下面咱們看一下測試結果。
運行結果
最大值測試

最小值測試

完整代碼
[java] view plain copy
print?
- /**
- *@Description: 雙邊匹配決策算法
- */
- package com.lulei.twosided.matching.decisionmaking;
-
- import com.lulei.util.JsonUtil;
-
- public class TwoSidedDecision {
- private int num = 10;//個體數目
- private boolean maxFlag = true;//是否求最大值
- private int[][] scoreArray;//AB之間的互評得分
- private int[] decisionArray;//A選擇B的方式
-
- public boolean isMaxFlag() {
- return maxFlag;
- }
-
- public void setMaxFlag(boolean maxFlag) {
- this.maxFlag = maxFlag;
- }
-
- /**
- * @return
- * @Author:lulei
- * @Description: 得到最後的決策
- */
- public int[] getDecisionArray() {
- return decisionArray;
- }
-
- /**
- * @return
- * @Author:lulei
- * @Description: 獲取決策的評分
- */
- public int getScoreSum() {
- int sum = 0;
- for (int i = 0; i < num; i++) {
- sum += scoreArray[i][decisionArray[i]];
- }
- return sum;
- }
-
- /**
- * @param num
- * @Author:lulei
- * @Description: 設置雙邊決策個體個數
- */
- public void setNum(int num) {
- if (num < 1) {
- System.out.println("num must be greater than 0");
- return;
- }
- this.num = num;
- }
-
- /**
- * @param scoreArray
- * @Author:lulei
- * @Description: 設置A類個體與B類個體間的評價
- */
- public void setScoreArray(int[][] scoreArray) {
- if (scoreArray == null) {
- System.out.println("scoreArray is null");
- }
- if (!(scoreArray.length == num && scoreArray[0].length == num)) {
- System.out.println("scoreArray`s must be " + num);
- }
- this.scoreArray = scoreArray;
- decisionArray = new int[num];
- //初始決策,對角線
- for (int i = 0; i < num; i++) {
- decisionArray[i] = i;
- }
- decision();
- }
-
- /**
- * @Author:lulei
- * @Description: 計算最優決策
- */
- private void decision() {
- if (scoreArray == null || decisionArray == null) {
- System.out.println("please init scoreArray");
- }
- for (int stepSize = 1; stepSize < num; stepSize++) {
- //特定步長下的交換
- while (compare(stepSize));
- }
- }
-
- /**
- * @param stepSize
- * @return
- * @Author:lulei
- * @Description: 特定步長比較,返回值確認是否發生交換
- */
- private boolean compare(int stepSize) {
- for (int i = 0; i < num - stepSize; i++) {
- int a1 = i;
- int a2 = i + stepSize;
- int b1 = decisionArray[a1];
- int b2 = decisionArray[a2];
- //原始兩個得分之和
- int score1 = scoreArray[a1][b1] + scoreArray[a2][b2];
- int between1 = Math.abs(scoreArray[a1][b1] - scoreArray[a2][b2]);
- //交換後的兩個得分之和
- int score2 = scoreArray[a1][b2] + scoreArray[a2][b1];
- int between2 = Math.abs(scoreArray[a1][b2] - scoreArray[a2][b1]);
- if (maxFlag) { //最後的得分最大
- if (score1 <= score2) {//交換後的分數不小於交換前的
- //交換後的分數大於交換前的或者交換後的差值大於交換前的
- if (score1 < score2 || between2 > between1) {
- decisionArray[a1] = b2;
- decisionArray[a2] = b1;
- return true;
- }
- }
- } else { //最後的得分最小
- if (score1 >= score2) {//交換後的分數不小於交換前的
- //交換後的分數大於交換前的或者交換後的差值大於交換前的
- if (score1 > score2 || between2 > between1) {
- decisionArray[a1] = b2;
- decisionArray[a2] = b1;
- return true;
- }
- }
- }
- }
- return false;
- }
-
- public static void main(String[] args) {
- int[][] scoreArray = {
- {0,1,2,3,4,5,6,7,8,9},
- {1,2,3,4,5,6,7,8,9,0},
- {2,3,4,5,6,7,8,9,0,1},
- {3,4,5,6,7,8,9,0,1,2},
- {4,5,6,7,8,9,0,1,2,3,},
- {5,6,7,8,9,0,1,2,3,4},
- {6,7,8,9,0,1,2,3,4,5},
- {7,8,9,0,1,2,3,4,5,6},
- {8,9,0,1,2,3,4,5,6,7},
- {9,0,1,2,3,4,5,6,7,8}};
- TwoSidedDecision test = new TwoSidedDecision();
- test.setNum(10);
- test.setMaxFlag(false);
- test.setScoreArray(scoreArray);
- System.out.println("最優決策");
- System.out.println(JsonUtil.parseJson(test.getDecisionArray()));
- System.out.println("決策得分");
- System.out.println(test.getScoreSum());
- }
-
- }