scau 8616 汽車拉力比賽

      上次咱們過了二分圖的最佳匹配,如今咱們看一道題目,經典的二分圖的最佳匹配題目算法

8616 汽車拉力比賽

時間限制:500MS  內存限制:1000K
提交次數:71 經過次數:24編程

題型: 編程題   語言: G++;GCC數組

 

Description

 SCAU車隊要去參加汽車拉力比賽啦。拉力比賽中,每輛汽車須要一個駕駛員和一個導航員。SCAU車隊一共有有N個駕駛員和N個導航員,每一個 駕駛員對每一個導航員有一個默契值,如今須要求得某種N對N的配對,使得這N個配對的默契值之和最大。 

ide

輸入格式

 多Case,每個Case第一行是一個整數N,範圍是(1<=N<=16)。接下來有N行,每行有N個數,第i行第j個數表示第i個駕駛員和第j個導航員的默契值。 測試數據會有多組,當N=0時表示數據結束,這行不用處理。

輸出格式

 輸出配對後默契值之和的最大值。

輸入樣例

1
5
2
10 20
25 5
0

輸出樣例

5
45
至於如何作,我就不說了,看看我之前的博客吧,思路應該很清晰的
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define inf 99999
//保存一個咱們認爲的無窮大
int n;
int match[50];//表示這個[駕駛員]搭配那個駕駛員
int e[50][50];//用來保存一張圖,表示i-->j的默契值
int vx[50];//用來表示 駕駛員 來找過partner
int vy[50];//用來表示 導航員 被邀請過搭配
int fx[50];//一開始是用來表示每個駕駛員與1--n個導航員的max,可是隨着程序執行,會變化哦
int fy[50];//一開始是0的。咱們稱這兩個東西爲 標幹
int dfs (int u)//我要來找u的partner
{
    vx[u]=1;//u已經來找過partner啦,標記一下先,待會的km算法須要
    int i;
    for (i=1;i<=n;i++)//篩選n個 導航員  能夠知道,駕駛員比較「主動」
    {
        if (vy[i]==0&&fx[u]+fy[i]==e[u][i])//這個導航員沒有被邀請過..導航員爲u
        //駕駛員和導航員的【標槓】值相加,有這個默契值的話,這樣選出來的是最優的
        {
            //vy[i]==1;//這個導航員被邀請過了,可是,接不接受?仍是另一回事
            //不是等於等於
            //由於他還多是被別人搭配了嘛
            vy[i]=1;
            if (match[i]==0||dfs(match[i]))//若是他沒被人搭配了或者,它能夠找其餘人搭配
            {
                match[i]=u;//i搭配u  改變條件的
                //意思就是導航員i和駕駛員u搭配
                return 1;//搭配成功
            }
        }
    }
    return 0;//我找不到啊,後面,就會執行km
}
void do_km()//km算法
//對每個在vx[]數組中的駕駛員,咱們對他進行操做
//操做對象是每個不在vy[]數組中的導航員,在了的導航員是不能動的,是當前的最優解
{
    int i,j;
    int d;//表示默契值減少得最多,就是,搭配最大
    d=inf;//認爲他是無限大
    for (i=1;i<=n;i++)//遍歷每個駕駛員
    {
        if (vx[i]==1)//表示他是遍歷過的
        {
            for (j=1;j<=n;j++)//對他進行遍歷導航員
            {
                if (!vy[j])//沒有vy過的導航員才操做
                {
                   if (d>(fx[i]+fy[j]-e[i][j]))//對於後面沒vy的導航員,選出最小差值
                   {
                       d=fx[i]+fy[j]-e[i][j];
                       //printf ("%d\n",d);
                   }
                }
            }
        }
    }
    //對於每個vx[]的 fx[] 減去d
    //對於每個vy[]的 fy[] 加上d
    //這樣,總值會減少哦,就是,咱們有機會加入新的導航員,留下空位
    for (i=1;i<=n;i++)
    {
        if (vx[i]==1)
        {
            fx[i] -= d;
            vx[i]=0;//請0
        }
        if (vy[i]==1)//是訪問過的哦
        {
            fy[i] += d;
            vy[i]=0;//情0
        }
    }
    return ;
}
void work ()
{
    int i,j;
    memset (e,0,sizeof(e));
    memset (vx,0,sizeof(vx));
    memset (vy,0,sizeof(vy));
    memset (fx,0,sizeof(fx));
    memset (fy,0,sizeof(fy));
    memset (match,0,sizeof(match));

    for (i=1;i<=n;i++)
    {
        for (j=1;j<=n;j++)
        {
            scanf ("%d",&e[i][j]);//不是無向圖哦,有向的
            //就是e[i][j]!=e[j][i]  有可能相等
        }
    }
    //km算法的一部分,先初始化fx,fy
    for (i=1;i<=n;i++)//遍歷每個駕駛員
    {
        fy[i]=0;
        fx[i]= -inf;//無窮小
        for (j=1;j<=n;j++)//遍歷每個導航員
        {
             if (fx[i]<e[i][j])//默契值
             {
                 fx[i]=e[i][j];
             }
        }
    }
    for (i=1;i<=n;i++)//遍歷每個駕駛員
    {
        memset (vx,0,sizeof(vx));//每個駕駛員都是新的開始
        memset (vy,0,sizeof(vy));//要清零,
        while (!dfs(i))//若是他找不到搭配,就實現km算法
        {
            do_km();//km完後,仍是會對這個想插入的節點進行dfs的,由於他還沒搭配成功嘛
        }
    }
    //進行計數
    //如今match[i]記錄的是[導航員i]和[駕駛員match[i]]搭配
    int ans=0;
    for (i=1;i<=n;i++)//遍歷導航員
    {
        ans += e[match[i]][i];//輸入的第一個是駕駛員,第二個是導航員
    }
    printf ("%d\n",ans);
    return ;
}
int main ()
{
    while (scanf ("%d",&n)!=EOF && n)
    {
        work ();
    }
    return 0;
}
View Code
相關文章
相關標籤/搜索