美团--订单分配
美團–訂單分配
文章目錄
- 美團--訂單分配
- 一、題目描述
- 二、分析
- 三、代碼
一、題目描述
打車派單場景, 假定有N個訂單, 待分配給N個司機。每個訂單在匹配司機前,會對候選司機進行打分,打分的結果保存在N*N的矩陣A, 其中A[i][j] 代表訂單i司機j匹配的分值。
假定 每個訂單只能派給一位司機,司機只能分配到一個訂單。求最終的派單結果,使得匹配的訂單和司機的分值累加起來最大,并且所有訂單得到分配。
- 輸入描述:
- 輸出描述:
二、分析
- 注意題中的一個條件“每個訂單只能派給一位司機,司機只能分配到一個訂單”,因為N*N的矩陣A中保存著每個顧客對司機的打分情況,而A[i][j] 代表訂單i司機j匹配的分值。
- 這就意味著我們在A數組中進行選擇的時候每一行每一列只能選擇一個
- 那么這個問題就和n皇后問題、全排列問題基本上是一致的了,是一個典型的回溯算法的思路,求所有排列當中結果最大的一種情況
- 直接看代碼:
三、代碼
#include <iostream> #include <algorithm> #include <string> #include <vector> #include <stack> #include <queue> using namespace std;void backTrack(vector<vector<double>>& num,vector<bool>&used, vector<int>& pre,vector<int>& cur,double curProfit, double&preProfit, int n, int pos) {//如果pos == n 說明行數已經達到n行,所有的行都已經選完,是一種結果if (pos == n) {//全局找最大,判斷是否出現更優解if (curProfit > preProfit) {//更新當前最大的和preProfit = curProfit;//數組賦值,將這個最優解的數組賦值給pre,最后用來輸出pre = cur; }return;}//枚舉第pos行的每一列for (int i = 0; i < n; i++){//改行必須在之前沒有被選擇使用過,必須滿足題意if (!used[i]) // 標記第 i列,下一次第i列就不能選擇了{//代表本次選擇pos行的i列元素,進行標記本次遞歸的選擇位置//因為可能出現本次選擇是最優的情況,所以需要保存cur[pos] = i; // 記錄每一個 pos行對應的列數i,下面的就是回溯過程//代表當前的評分和加上本次的選擇//同理和cur一樣都要保存curProfit += num[pos][i];//代表著第i例被使用過,下次不能在選擇第i列used[i] = true;backTrack(num,used,pre,cur, curProfit, preProfit, n, pos + 1);//撤銷選擇curProfit -= num[pos][i];//撤銷標記used[i] = false;}} }int main() {int n;while (cin >> n){vector<vector<double>> vvd(n, vector<double>(n));for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){cin >> vvd[i][j];}}vector<int> pre(n); // 記錄最優解的每個值 所在的 列數vector<int> cur(n); // 列數加入數組vector<bool> used(n); // 標記數組, 因為一列只能選擇一個double preProfit = INT_MIN; // 全局的最大值double curProfit = 0.0; // 當前的最大值int pos = 0; // pos就是行數,pos到達一行,就選y值就可以了backTrack(vvd, used, pre, cur, curProfit, preProfit, n, pos); //打印結果printf("%4.2f\n",preProfit);//cout << preProfit << endl;for (int i = 0; i < pre.size(); i++){cout << i + 1 << " " << pre[i] + 1 << endl;}} }總結
- 上一篇: 力扣--扁平化嵌套列表迭代器
- 下一篇: 美团--美团骑手包裹区间分组