打车派单场景, 假定有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;
} 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.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;
} 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重写的话应该就过了。