1. 程式人生 > >帶權的二分圖的最優匹配KM演算法

帶權的二分圖的最優匹配KM演算法

/*********************************************************
演算法引入:
給定一個完全二分圖G=(X∪Y,X×Y),其中邊(x,y)有權w(x,y);
要找一個從X到Y具有最大權和的匹配M,即為二分圖的最優匹配問題;
KM(Kuhn_Munkras)演算法求的是完備匹配下的最大權匹配;

演算法思想:
KM演算法是通過給每個頂點一個標號(叫做頂標)來把求最大權匹配的問題轉化為求完備匹配的問題的;
設頂點Xi的頂標為A[i],頂點Yi的頂標為B[i],頂點Xi與Yj之間的邊權為w[i,j];
在演算法執行過程中的任一時刻,對於任一條邊(i,j),A[i]+B[j]>=w[i,j]始終成立;
初始A[i]為與Xi相連的邊的最大邊權,B[j]=0;

KM演算法的正確性基於以下定理:
設G(V,E)為二分圖,G'(V,E')為該二分圖的子圖;
如果對於G'中的任何邊<x,y>滿足, A(x)+ B(y)==W[x,y];
則稱G'(V,E')為G(V,E)的等價子圖或相等子圖(是G的生成子圖);
若由二分圖中所有滿足A[i]+B[j]=w[i,j]的邊(i,j)構成的子圖(稱做相等子圖)有完備匹配;
那麼這個完備匹配就是二分圖的最大權匹配;

因為對於二分圖的任意一個匹配,如果它包含於相等子圖;
那麼它的邊權和等於所有頂點的頂標和;
如果它有的邊不包含於相等子圖,那麼它的邊權和小於所有頂點的頂標和(即不是最優匹配);
所以相等子圖的完備匹配一定是二分圖的最大權匹配;

相等子圖包含原圖的所有的點,相等子圖一定可以找到完備匹配;
相等子圖的完備匹配只需加一些虛擬點可以擴充為完美匹配(記為M);
完美匹配是包含了所有點的匹配,那麼所有點的頂點的標號值都包括進來了;
雖然有些點是0,在這個狀態下,把相等子圖的標號一一對應的標到原圖上去;
原圖的任意一個匹配最多隻能包含原圖的所有頂點;
即任何匹配的權和不可能超過所有標號的和,所以M的和必然是最優的;

演算法改進:
給每個Y頂點一個"鬆弛量"函式slack;
每次開始找增廣路時初始為無窮大;
在尋找增廣路的過程中,檢查(i,j)時,如果它不在相等子圖中;
則讓slack[j]=min(原值,A[i]+B[j]-W[i,j]);
這樣在修改頂標時,取所有的不在交錯樹中的Y頂點的slack值中的最小值作為d值即可;

演算法過程:
①初始化可行頂標的值;
②用匈牙利演算法尋找完備匹配;
③若未找到完備匹配則修改可行頂標的值;
④重複②③直到找到相等子圖的完備匹配;
**********************************************************/
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<climits>
#include<algorithm>
using namespace std;

const int N = 1000;
const int INF = 0xffffff;
int w[N][N];//權值
int lx[N],ly[N]; //頂標
int linky[N];//記錄與i匹配的頂點
int visx[N],visy[N];
int slack[N];//鬆弛量
int nx,ny;//二分圖兩邊的頂點數

void init()
{
    memset(linky,-1,sizeof(linky));//記錄與i匹配的頂點
    memset(ly,0,sizeof(ly));///初始化頂標y為0
    for(int i = 0; i < nx; i++)
        for(int j = 0,lx[i] = -INF; j < ny; j++)
        {
            if(w[i][j] > lx[i])
                lx[i] = w[i][j];///初始化頂標x為與頂點Xi關聯的邊的最大權
        }

}

bool find(int x)//匈牙利演算法
{
    visx[x] = true;
    for(int y = 0; y < ny; y++)
    {
        if(visy[y])
            continue;
        int t = lx[x] + ly[y] - w[x][y];//若t==0,則為最大權匹配;

        if(t==0)
        {
            visy[y] = true;
            if(linky[y]==-1 || find(linky[y]))
            {
                linky[y] = x;
                return true;        //找到增廣軌
            }
        }

        else if(slack[y] > t)
            slack[y] = t;
    }
    return false;                   //沒有找到增廣軌(說明頂點x沒有對應的匹配,與完備匹配(相等子圖的完備匹配)不符)
}

int KM()                //返回最優匹配的值
{
    init();
    for(int x = 0; x < nx; x++)
    {
        for(int i = 0; i < ny; i++)
            slack[i] = INF;//鬆弛函式初始化為無窮大

        while(1)
        {
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(find(x))                     //找到增廣軌,退出
                break;
            int d = INF;
            for(int i = 0; i < ny; i++)          //沒找到,對l做調整(這會增加相等子圖的邊),重新找
            {
                if(!visy[i] && d > slack[i])
                    d = slack[i];
            }
            for(int i = 0; i < nx; i++)//修改x的頂標
            {
                if(visx[i])
                    lx[i] -= d;
            }
            for(int i = 0; i < ny; i++)//修改y的頂標
            {
                if(visy[i])
                    ly[i] += d;
                else
                    slack[i] -= d;//修改頂標後,不在交錯樹中的y頂點的slack值都要減去d;
            }
        }

    }

    int result = 0;
    for(int i = 0; i < ny; i++)
    {
        if(linky[i]>-1)
            result += w[linky[i]][i];
    }
    return result;
}

int main()
{
    //freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin);
    while(~scanf("%d%d",&nx,&ny))
    {
        if(!nx||!ny)
            break;
        int a,b,c;
        while(scanf("%d%d%d",&a,&b,&c),a+b+c)
        {
            w[a][b]=c;
        }
        printf("%d\n",KM());
    }
    return 0;
}

相關推薦

HDU2255 奔小康賺大錢 (二分匹配) 模板題【KM演算法

<題目連結>               奔小康賺大錢 Problem Description 傳 說在遙遠的地方有一個非常富裕的村落,有一天,村長決定進行制度改革:重新分配房子。 這可是一件大事,關係到人民的住房問題啊。村裡共有n間房間,剛好有n家老百姓,考慮到每家都要有

UVA1349(二分匹配 --> KM算法模板)

amp slack == 還需要 構造 有一個 using lac str UVA1349 題意:給定一些有向帶權邊,求出把這些邊構造成一個個環,總權值最小 解法: 對於帶權的二分圖的匹配問題可以用通過KM算法求解。 要求最大權匹配就是初始化g[i][j]為0,直接跑就可以

二分匹配 P1500

author ges double its 一個 rip const 方式 empty 帶權二分圖最大匹配 P1500 普通的二分圖最大匹配的權值都是1,但是現在我們要解決帶權的。 解決方法有兩個:一個是匈牙利算法但是不會,另一個是最大費用最大流。 建圖方式是這個樣子:

二分匹配KM演算法

/********************************************************* 演算法引入: 給定一個完全二分圖G=(X∪Y,X×Y),其中邊(x,y)有權w(x,y); 要找一個從X到Y具有最大權和的匹配M,即為二分圖的最優匹配問題;

二分的最佳匹配KM演算法

還是沒看懂一般圖都是最大匹配問題。。怪我太笨了哎~ 先來個看明白了的KM演算法——尋找帶權二分圖的最佳匹配方法 一般對KM演算法的描述,基本上可以概括成以下幾個步驟: (1) 初始化可行標杆 (2) 用匈牙利演算法尋找完備匹配 (3) 若未找到完備匹配則修改可行標杆 (4)

HDU3488 Tour —— 二分大權匹配 KM算法

sed exceptio total icpc def i++ after ive pac 題目鏈接:https://vjudge.net/problem/HDU-3488 Tour Time Limit: 3000/1000 MS (Java/Others) M

[SDOI2017]新生舞會,洛谷P3705,分數規劃+二分匹配

正題       題目連結點這裡       給出兩個矩陣a,b,都表示i和j之間的權值,要求構造一個排列P,使得最大。       我們來二分一個mid,使得,然後變形金剛,  

學習筆記第十二節:二分匹配

正題       看到這個題目,會覺得可以直接用綠與被綠匈牙利演算法來解決。       但是當我們遇到,“第i個人和第j個物品會產生g[i][j]的價值,求完全匹配的最小价值”的時候。       我們就需要用到二分圖最優匹配的演算法了。       這個演算法的複

HDU2389:Rain on your Parade(二分匹配+HK演算法

Rain on your Parade Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 655350/165535 K (Java/Others)Total Submission(s): 5755&nbs

二分匹配 匈牙利演算法的簡單理解

(本文圖片及被*標註內容來自CSDN部落格:pi9nc) 基本概念—二分圖 二分圖:是圖論中的一種特殊模型。若能將無向圖G=(V,E)的頂點V劃分為兩個交集為空的頂點集,並且任意邊的兩個端點都分屬於兩個集合,則稱圖G為一個為二分圖。 匹配:一個匹配即一個包含若干條邊的集合,且其中任

過山車 (二分匹配 匈牙利演算法

開始時比較難理解的演算法 原題:過山車 題意:n個女生,m個男生,每個女生都有幾個固定的可以搭配的男生,有k組搭配總共,輸入a,b代表a女生可以和b男生搭配,問最後最多有幾對搭配。 先附程式碼: int head_g[N]; int now_g;

匈牙利演算法(求二分匹配演算法

匈牙利演算法是由匈牙利數學家Edmonds於1965年提出,因而得名。匈牙利演算法是基於Hall定理中充分性證明的思想,它是二部圖匹配最常見的演算法,該演算法的核心就是尋找增廣路徑,它是一種用增廣路徑求二分圖最大匹配的演算法。 設 G=(V,E) 是一個無向

(通俗易懂小白入門)二分匹配——匈牙利演算法

二分圖  先介紹一下什麼是二分圖,二分圖也叫二部圖,設G=(V,E)是一個無向圖,如果頂點V可分割為兩個互不相交的子集(A,B),並且圖中的每條邊(i,j)所關聯的兩個頂點i和j分別屬於這兩個不同的頂點集(i in A,j in B),則稱圖G為一個二分圖,如下圖所有的頂點可以分成A,B兩個集合,而

HDU 1853 & HDU 3488【有向環值覆蓋問題 】二分匹配 KM演算法

In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000) one-way roads connecting them. You are lucky

KM演算法二分匹配(完備匹配

1.基礎知識普及 二分圖的概念 二分圖又稱作二部圖,是圖論中的一種特殊 模型。 設G=(V,{R})是一個無向圖。如頂點集V可分 割為兩個互不相交的子集,並且圖中每條邊 依附的兩個頂點都分屬兩個不同的子集。則圖G成為二分圖。 通俗來講,二分圖指的是這樣一種

二分大合集——二分匹配小覆蓋數),完美匹配以及匹配匹配

二分圖: 定義:二分圖又稱作二部圖,是圖論的一種特殊模型。設G=(V, E)是一個無向圖,如果頂點V可分割為兩個互不相交的子集(A , B),且圖中的每條邊(i, j)所關聯的兩個定點分別屬於這兩個不同的頂點集(i in A, j in B),則稱圖G為一個二

二分匹配 Kuhn-Munkres演算法

分工問題如下:某公司有工作人員x1,x2,...,xn,他們去做工作y1,y2,...,yn,每人適合做其中的一項或幾項工作,每個人做不同的工作的效益不一樣,我們需要制定一個分工方案,使公司的總效益最大,這就是所謂最佳分配問題, 它們數學模型如下: 數學模型:    G是加權完全二分圖,V(G)的二分圖

二分匹配KM演算法

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int IN

km板子(二分大權匹配

define != tdi push_back air base long temp 匹配 //#pragma comment(linker, "/stack:200000000") //#pragma GCC optimize("Ofast,

[NOI2012]美食節——費用流(二分匹配)+動態加邊

最大 set sin 最短路 最大流 pre 可能 題目 不同 題目描述 小M發現,美食節共有n種不同的菜品。每次點餐,每個同學可以選擇其中的一個菜品。總共有m個廚師來制作這些菜品。當所有的同學點餐結束後,菜品的制作任務就會分配給每個廚師。然後每個廚師就會同時開始做菜。廚師