工作分配問題【回溯算法】

  • Problem Description

設有n件工作分配給n個人。將工作i分配給第j個人所需的費用爲 c i j c_{ij} cij。試設計一個算法,爲每一個人都分配1件不同的工作,並使總費用達到最小。
設計一個算法,對於給定的工作費用,計算最佳工作分配方案,使總費用達到最小。

Input
輸入數據的第一行有1 個正整數n (1≤n≤20)。接下來的n行,每行n個數,表示工作費用。
Output
將計算出的最小總費用輸出。


Sample Input

3
10 2 3
2 3 4
3 4 5

Sample Output

9
  • 解題思路

爲工作 i 安排第 j 個人的解決方法與“運動員最佳匹配問題”類似,讓一方選另一方,這樣就可以構成一棵排列樹。我們讓工作“選”人,那排列樹的結點代表人,而層就代表工作。如下圖左上角的G1表示工人1,且在第一層,表示爲工作 1 安排第 1 個人,即將工作1分配給工人1。

  • 樣例分析

在這裏插入圖片描述

注:由上可知,最小值可能有多個,但效果一樣,最終返回的都是9

  • 代碼實現

#include <bits/stdc++.h>
using namespace std;

int n;
int pay[21][21];   //pay[i][j]表示將工作i分配給第j個人的費用爲pay[i][j]
int Min=INT_MAX;   //因爲要求最小值,所以將Min初始化爲最大整數(int型)
int sum=0;   //記錄搜索過程中得到的工作費用和
int book[21];   //用於標記一個人是否已被分配工作:book[i]=0表示沒有被分配工作;book[i]=1表示已經被分配工作

void dfs(int t)
{
   
   
    if(t>=n)   //已經到達葉子結點,繼續判斷是否找到了最小總費用
    {
   
   
        if(Min>sum)   //沒有找到最小總費用
        {
   
   
            Min=sum;   //更新最小總費用
            return;
        }
    }
    for(int i=0;i<n;i++)   //爲第工作t安排人
    {
   
   
        if(!book[i])   //第i個人還沒有被安排工作
        {
   
   
            book[i]=1;   //將工作t分配給第i個人
            sum+=pay[t][i];   //更新總費用
            if(sum<Min)   //如果當前得到的sum小於最小值,就向下搜索子樹;否則剪枝
                dfs(t+1);
            book[i]=0;   //沒有得到比Min更小的和,回溯
            sum-=pay[t][i];
        }
    }

}

int main()
{
   
   
    cin>>n;
    for(int i=0;i<n;i++)
    {
   
   
        for(int j=0;j<n;j++)
        {
   
   
            cin>>pay[i][j];
        }
        book[i]=0;
    }
    dfs(0);
    cout<<Min<<endl;
    return 0;
}
  • 運行結果在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章