打车派单场景, 假定有N个订单, 待分配给N个司机。每个订单在匹配司机前,会对候选司机进行打分,打分的结果保存在N*N的矩阵A, 其中Aij 代表订单i司机j匹配的分值。
假定每个订单只能派给一位司机,司机只能分配到一个订单。求最终的派单结果,使得匹配的订单和司机的分值累加起来最大,并且所有订单得到分配。
打车派单场景, 假定有N个订单, 待分配给N个司机。每个订单在匹配司机前,会对候选司机进行打分,打分的结果保存在N*N的矩阵A, 其中Aij 代表订单i司机j匹配的分值。
假定每个订单只能派给一位司机,司机只能分配到一个订单。求最终的派单结果,使得匹配的订单和司机的分值累加起来最大,并且所有订单得到分配。
第一行包含一个整数N,2≤N≤10。
第二行至第N+1行包含N*N的矩阵。
输出分值累加结果和匹配列表,结果四舍五入保留小数点后两位(注意如果有多组派单方式得到的结果相同,则有限为编号小的司机分配编号小的订单,比如:司机1得到1号单,司机2得到2号单,就比司机1得到2号单,司机2得到1号单要好)
3 1.08 1.25 1.5 1.5 1.35 1.75 1.22 1.48 2.5
5.25 1 2 2 1 3 3
第一行代表得到的最大分值累加结果5.25,四舍五入保留两位小数;
第二行至第四行代表匹配的结果[i j],其中i按行递增:
订单1被派给司机2,订单2被派给司机1,订单3被派给司机3。使得A12+ A21+ A33= 1.25 + 1.5 + 2.5 = 5.25在所有的组合中最大。
#include<bits/stdc++.h> using namespace std; vector<int>res; vector<bool>tag; double rmax=0; void solve(vector<vector<double>>&A,vector<int>&v,double maxnum,int j){ if(j>=A[0].size()){ if(rmax<maxnum){ rmax=maxnum; res=v; } return; } for(int i=0;i<A[0].size();i++){ if(!tag[i]){ tag[i]=true; v.push_back(i); solve(A,v,maxnum+A[j][i],j+1); v.pop_back(); tag[i]=false; } } } int main(){ int n; double a; cin>>n; vector<vector<double> >A; for(int i=0;i<n;i++){ vector<double>temp; for(int j=0;j<n;j++){ cin>>a; temp.push_back(a); } A.push_back(temp); } vector<int>v; tag=vector<bool>(n,false); solve(A,v,0,0); cout<<fixed<<setprecision(2)<<rmax<<endl; for(int i=0;i<n;i++)cout<<i+1<<" "<<res[i]+1<<endl; return 0; }
import java.util.*; //过100% public class Main { private double t = 0.00; private int[] flag; private double res = -1000.00;//0.00只能过80% private ArrayList<Integer> add; public void Solution(double[][] nums) { int n = nums.length; flag = new int[n]; for(int i = 0;i<n;i++) { ArrayList<Integer> temp = new ArrayList<>(); temp.add(i+1); flag[i] = 1; t = nums[0][i]; Best(temp, nums, 1); t = 0.00; flag[i] = 0; } System.out.println(String.format("%.2f", res)); for(int i = 0;i<add.size();i++) { System.out.println(i+1 +" "+ add.get(i)); } } public void Best(ArrayList<Integer> temp, double[][] nums, int end) { if(end==nums.length) { if(res<t) { res = t; add = (ArrayList<Integer>) temp.clone(); } } for(int i = 0;i<nums.length;i++) { if(flag[i]!=1) { flag[i] = 1; t += nums[end][i]; temp.add(i+1); Best(temp, nums, end+1); temp.remove(temp.size()-1); t -= nums[end][i]; flag[i] = 0; } } } public static void main(String[] args) { Scanner in = new Scanner(System.in); while(in.hasNext()) { int n = in.nextInt(); double[][] nums = new double[n][n]; for(int i = 0;i<n;i++) for(int j = 0;j<n;j++) nums[i][j] = in.nextDouble(); Main s = new Main(); s.Solution(nums); } } }参考楼上的答案,修改了初始值后,过100%
import java.util.*; public class Main { private double t = 0.00; private int[] flag; private double res = 0.00; private ArrayList<Integer> add; public void Solution(double[][] nums) { int n = nums.length; flag = new int[n]; for(int i = 0;i<n;i++) { ArrayList<Integer> temp = new ArrayList<>(); temp.add(i+1); flag[i] = 1; t += nums[0][i]; Best(temp, nums, 1); t = 0.00; flag[i] = 0; } System.out.println(String.format("%.2f", res)); for(int i = 0;i<add.size();i++) { System.out.println(i+1 +" "+ add.get(i)); } } public void Best(ArrayList<Integer> temp, double[][] nums, int end) { if(end==nums.length) { if(res<t) { res = t; add = (ArrayList<Integer>) temp.clone(); } } for(int i = 0;i<nums.length;i++) { if(flag[i]!=1) { flag[i] = 1; t += nums[end][i]; temp.add(i+1); Best(temp, nums, end+1); temp.remove(temp.size()-1); t -= nums[end][i]; flag[i] = 0; } } } public static void main(String[] args) { Scanner in = new Scanner(System.in); while(in.hasNext()) { int n = in.nextInt(); double[][] nums = new double[n][n]; for(int i = 0;i<n;i++) for(int j = 0;j<n;j++) nums[i][j] = in.nextDouble(); Main s = new Main(); s.Solution(nums); } } }不是知道为什么越界 求大佬看看
#include<bits/stdc++.h> using namespace std; double dp[15][1<<12]; //表示到第i个司机时时1~i的司机的选择情况,用二进制表示,当前位为1,则代表被选了 double a[15][15]; const double inf=1e9; int calc(int x){ //计算x二进制有多少个1 int t=0; while(x){ t+=x&1; x>>=1; } return t; } int fa[15][1<<12]; //用来记录当前状态由哪个状态转移过来,方便之后的路径查找 typedef pair<int,int>pii; vector<pii>V; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) scanf("%lf",&a[i][j]); } dp[0][0]=0; int sz=1<<n; for(int i=1;i<=n;i++){ for(int j=0;j<sz;j++){ dp[i][j]=-inf; } } for(int i=1;i<=n;i++){ for(int j=1;j<sz;j++){ if(calc(j)!=i){ //因为到第i个司机只能是有i个订单被选了 continue; } //cout<<i<<" "<<j<<endl; for(int k=1;k<=n;k++){ //当前枚举的状态中第k个订单没被选,则跳过 if((j&(1<<(k-1)))==0)continue; //当前枚举的状态第k个订单被选了,则由1~(i-1)的没选k的状态转移过来,因此异或掉 int tmp=j^(1<<(k-1)); if(dp[i][j]<dp[i-1][tmp]+a[n-i+1][k]){ //只有在更优的时候选择,保证一定先选订单号小的 dp[i][j]=dp[i-1][tmp]+a[n-i+1][k]; //cout<<i<<" "<<j<<" "<<k<<endl; fa[i][j]=tmp; } } } } //fj代表最终状态 即111111... int fj=sz-1; //这里就在迭代求路径,由转移的记录来找,注意的是一直是把最后一个司机当第一个司机的 for(int i=n;i>=1;i--){ int tmp=fa[i][fj]; for(int j=1;j<=n;j++){ //tmp^fj就能计算出当前这个司机选的是哪个订单(例如00010000)之类的,然后找一下是不是j这个订单 if((1<<(j-1))&(tmp^fj)){ V.push_back({n-i+1,j}); break; } } fj=tmp; } printf("%.2f\n",dp[n][sz-1]); sort(V.begin(),V.end()); for(auto var:V){ printf("%d %d\n",var.first,var.second); } return 0; }
//每行每列选一个,且不重复,类似于N皇后问题与全排列问题,回溯法解决 #include <iostream> #include <vector> #include <stdio.h> using namespace std; void recur(vector<vector<double>>& nums, vector<int>& ans, vector<int>& curT, vector<bool>& visited, double curProfit, double& sum, int row){ int n = nums.size(); //退出条件 if(row == n){ if(curProfit > sum){ //更新最大和与每行对应的列 sum = curProfit; ans = curT; } return; } //轮流考虑当前row行,选取每一列的可能性 for(int i=0; i<n; i++){ //该列未选取 if(!visited[i]){ //更新状态 visited[i] = true; curProfit += nums[row][i]; curT[row] = i; recur(nums, ans, curT, visited, curProfit, sum, row+1); //还原状态 visited[i] = false; curProfit -= nums[row][i]; } } } int main(){ int n; while(cin >> n){ vector<vector<double>> nums(n, vector<double>(n)); for(int i=0; i<n; i++){ for(int j=0; j<n; j++) cin >> nums[i][j]; } //最大和的情况下,各行选取的列; 当前状态下各行选取的列 vector<int> ans(n), curT(n); //记录已选取的列,避免重复 vector<bool> visited(n, false); //最大和与当前和 double sum = -1, curProfit = 0; //初始行号 int row = 0; recur(nums, ans, curT, visited, curProfit, sum, 0); printf("%4.2f\n", sum); for(int i=0; i<n; i++){ cout << i+1 << ' ' << ans[i]+1 << endl; } } return 0; }
import java.io.*; /** * @Description: 计算并保存所有分组方式下的 score 值,取最大值 优化方向 -> 循环计算并 始终存储一组最好的值 * @Param: * @return: * @Author: xulifeng * @Date: 3/10/2022 */ public class Main { // 原始分配表 static double[][] score; // 最终分配结果 static double[][] bestPath; // 当前分配方式 static double[][] curPath; // 最大score static double maxScore = 0; // 订单数 static int orderNum; public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); orderNum = Integer.parseInt(br.readLine()); score = new double[orderNum][orderNum]; bestPath = new double[orderNum][orderNum]; curPath = new double[orderNum][orderNum]; // 填充score、bestPath、curPath for (int i = 0; i < orderNum; i++) { String[] oneRowScore = br.readLine().split(" "); for (int j = 0; j < orderNum; j++) { score[i][j] = Double.parseDouble(oneRowScore[j]); bestPath[i][j] = 0; curPath[i][j] = 0; } } //从第0行开始递归 backTracing(0, orderNum); System.out.printf("%.2f",maxScore); System.out.println(); for (int i = 0; i < orderNum; i++) { for (int j = 0; j < orderNum; j++) { if (bestPath[i][j] != 0) { // +1是因为订单 车是从1开始 而数组从零开始 System.out.print(i+1); System.out.print(" "); System.out.println(j+1); } } } } /** * @Description: 回溯算法 检查这个位置是否还能存放 * @Param: 当前行curRow 总列数 * @return: * @Author: xulifeng * @Date: 3/9/2022 */ public static void backTracing(int curRow, int totalCol) { // 遍历完所有行时 row 和 col 大小一样 if (curRow == orderNum) { // 将深拷贝的数据添加进result 浅拷贝会因为回溯全部变为0 double curScore = computeCurScore(); if (curScore > maxScore) { maxScore = curScore; bestPath = deepCopy(); } return; } //index 其实也为行 从上往下判断 for (int index = 0; index < totalCol; index++) { if (isValid(curRow, index)) { // 可以分配订单 curPath[curRow][index] = score[curRow][index]; backTracing(curRow+1,totalCol); //撤销当前的操作 因为撤销操作 所有的bestPath数组最终都变成了0回溯不可避免的事情 curPath[curRow][index] = 0; } } } // 检查目前是否能在 row col这个位置存放数据 要求同一列只能有一个数据 public static boolean isValid(int curRow, int curCol){ //检查[curRow][curCol]这一列之前是否已经有数据 for (int i = 0; i < curRow; i++) { if (curPath[i][curCol] != 0) { return false; } } return true; } // 计算当前分配方式下的score public static double computeCurScore() { double score = 0; for (int i = 0; i < orderNum; i++) { for (int j = 0; j < orderNum; j++) { score += curPath[i][j]; } } return score; } // 深拷贝 public static double[][] deepCopy() { double[][] temp = new double[orderNum][orderNum]; for (int i = 0; i < orderNum; i++) { for (int j = 0; j < orderNum; j++) { temp[i][j] = curPath[i][j]; } } return temp; } }
#include<bits/stdc++.h> using namespace std; double s[10][10]; int num[10]; int numt[10]; int n; double ma; int main(){ // 输入参数 cin>>n; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ cin>>s[i][j]; } } for(int i=0;i<n;i++){ num[i]=i; numt[i]=i; } // 查询最大值 ma=-100000; do{ double sum=0; for(int i=0;i<n;i++){ sum+=s[i][num[i]]; } if(sum>ma){ for(int i=0;i<n;i++){ numt[i] = num[i]; } ma=sum; } }while(next_permutation(num,num+n)); // 找到 0 - N 所有的排列组合 找出最大的一个 printf("%.2lf\n",ma); for(int i=0;i<n;i++){ cout<<i+1<<" "<<numt[i]+1<<endl; } return 0; }
public class Main { public static List<Integer> best = new ArrayList<>(); public static void main(String[] args) { double[][] matrix = {{1.08, 1.25, 1.5}, {1.5, 1.35, 1.75}, {1.22, 1.48, 2.5}}; double grade = allPl(matrix, 0, new ArrayList<>(), 0); System.out.println(grade); best.stream().forEach(item -> System.out.println(item + 1)); } public static double allPl(double[][] matrix, double maxNum, List<Integer> res, double num) { if (res.size() == matrix.length && num > maxNum) { maxNum = num; best = new ArrayList<>(res); return maxNum; } for (int i = 0; i < matrix.length; i++) { if (res.contains(i)) { continue; } res.add(i); num += matrix[res.size() - 1][i]; maxNum = allPl(matrix, maxNum, res, num); res.remove(res.size() - 1); num -= matrix[res.size()][i]; } return maxNum; } }
import java.util.*; public class Main { static boolean[] visited; static double max = -1000; static int n; static double[][] nums; static List<int[]> relation = new ArrayList<>(); static List<int[]> maxRelation = new ArrayList<>(); public static void main(String[] args) { Scanner in = new Scanner(System.in); n = in.nextInt(); nums = new double[n][n]; visited = new boolean[n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { nums[i][j] = in.nextDouble(); } } helper(0, 0); System.out.println(String.format("%.2f", max)); for (int[] re: maxRelation) { System.out.println((re[0] + 1) + " " + (re[1] + 1)); } } private static void helper(int row, double count) { // 这个时候计算最大值 if (row == n) { if (count >= max) { if (count == 0) { max = count; List<int[]> list = new ArrayList<>(); for (int i = 0; i < n; i++) { int[] temp = new int[2]; temp[0] = i; temp[1] = i; list.add(temp); } maxRelation = new ArrayList<>(list); } else { max = count; maxRelation.clear(); maxRelation = new ArrayList<>(relation); } } // 这个时候记录订单 return; } for (int i = 0; i < n ; i++) { if (!visited[i]) { // 同时记录订单与司机的关系 int[] relationArr = new int[2]; relationArr[0] = row; relationArr[1] = i; relation.add(relationArr); visited[i] = true; helper(row + 1, count + nums[row][i]); relation.remove(relation.size() - 1); visited[i] = false; } } } }
#include<bits/stdc++.h> using namespace std; vector<int>path, ret; double max_ = -1; void dfs(vector<vector<double>>& num, int cur, int status, double sum) { if (cur == num.size()) { if (sum > max_) { max_ = sum; ret = path; } return; } for (int i = 0; i < num.size(); i++) { if (status & (1 << i))continue; path.push_back(i + 1); dfs(num, cur + 1, status | 1 << i, sum + num[cur][i]); path.pop_back(); } } int main() { int n; cin >> n; vector<vector<double>>num(n, vector<double>(n)); vector<vector<int>>path(n, vector<int>(n)); iota(path[0].begin(), path[0].end(), 1); for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cin >> num[i][j]; dfs(num, 0, 0, 0); cout << fixed<<setprecision(2)<<max_ << endl; for (int i = 0; i < ret.size(); i++) cout << i+1 << " " << ret[i] << endl; return 0; }
def assign_order(A: list): n = len(A) result = [] m = [-float('inf')] visited = [[0] * n] * n def dfs(cur, n, t, res): if cur > n: sumt = sum(t) if sumt > m[0]: m[0] = sumt result.append(res) return for i in range(n + 1): if not visited[cur][i]: visited[cur][i] = 1 dfs(cur + 1, n, t + [A[cur][i]], res + [i + 1]) visited[cur][i] = 0 dfs(0, n - 1, [], []) print('{:.2f}'.format(m[0])) for i in range(n): print('{} {}'.format(i + 1, result[-1][i])) n = int(input().strip()) matrix = [] for i in range(n): matrix.append(list(map(float, input().strip().split()))) assign_order(matrix)通过90%,后面超时,用JAVA重写的话应该就过了。