POJ 2400 KM最小權匹配+輸出所有配對方案

Supervisor, Supervisee
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 2407   Accepted: 681

Description

Suppose some supervisors each get to hire a new person for their department. There are N people to be placed in these N departments. Each supervisor interviews all N people, and ranks them according to how much she wants each of them in her department (1 being "really want" and N being "really don't want"). In turn, each of the N candidates ranks each of the supervisors as to how much that person would like to work for that supervisor (again, 1 is "really want to work for him/her" and N is "really don't want to work for him/her"). Given the scores that each supervisor has for each candidate, and the scores each candidate has for each manager, write a computer program to determine the "best match" of candidates to supervisors. The "best match" is determined by finding the distribution that leads to the highest overall (i.e. sum of) satisfaction for all people. The closer a person is to her number one choice, the better. If everyone gets their number one choice, the average difference will be 0.

Input

The first line of the input will contain a single integer greater than 0 specifying the number of test cases. 

The next line will contain a single integer value N, 0 < N < 15, representing the number of supervisors (and the number of employees - there are N supervisors and N employees). The next N lines will be the preferences of each of the N supervisors. Each line will contain N integer entries (1 through N for employees 1 through N), each separated by a space character, that represents the preferences of that supervisor from most preferred to least preferred. More specifically, the first entry on the line will represent that supervisor's first choice, the second entry her second, and so on. The next N lines will be the preferences of the N employees, in the same format as the supervisors. 

All lines of data in the input file will end with an empty line.

Output

For each test case, write the test case number (starting with 1) followed by the best average difference written to six digits of precision to the right of the decimal point. On the next line, show which best match it was (starting with 1). On the next N lines, show each supervisor (starting with 1) followed by the employee with which she was matched (1 per line). NOTE: if there is more than one best match, matches should be listed in ascending permuted order (see sample output). 

Separate each data set with an empty line.

Sample Input

2
7
1 2 3 4 5 6 7
2 1 3 4 5 6 7
3 1 2 4 5 6 7
4 1 2 3 5 6 7
5 1 2 3 4 6 7
6 1 2 3 4 5 7
7 1 2 3 4 5 6
1 2 3 4 5 6 7
2 1 3 4 5 6 7
3 1 2 4 5 6 7
4 1 2 3 5 6 7
5 1 2 3 4 6 7
6 1 2 3 4 5 7
7 1 2 3 4 5 6

2
1 2
2 1
1 2
1 2

Sample Output

Data Set 1, Best average difference: 0.000000
Best Pairing 1
Supervisor 1 with Employee 1
Supervisor 2 with Employee 2
Supervisor 3 with Employee 3
Supervisor 4 with Employee 4
Supervisor 5 with Employee 5
Supervisor 6 with Employee 6
Supervisor 7 with Employee 7

Data Set 2, Best average difference: 0.250000
Best Pairing 1
Supervisor 1 with Employee 1
Supervisor 2 with Employee 2

Source


分析:有點坑,兩個矩陣的輸入順序交換了。。。但對於題目本身並不難,首先KM求出最小權值匹配,然後dfs暴力求出匹配方案,細心一點就行。。。

代碼:

//複雜度O(n^3)
//其實在求最大 最小的時候只要用一個模板就行了,把邊的權值去相反數即可得到另外一個.求結果的時候再去相反數即可
//鄰接矩陣特別需要注意重邊的問題,切記
#pragma comment(linker,"/STACK:102400000,102400000")
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <string>
#include <math.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
typedef long long ll;   //記得必要的時候改成無符號
const int maxn=20;
const int INF=1000000000;
int n,nx,ny;
int march[maxn],lx[maxn],ly[maxn],slack[maxn];    //lx,ly爲頂標,nx,ny分別爲x點集y點集的個數
int visx[maxn],visy[maxn],w[maxn][maxn];

int dfs(int x)
{
    visx[x]=1;
    for(int y=1;y<=ny;y++)
    {
        if(visy[y])
            continue;
        int t=lx[x]+ly[y]-w[x][y];
        if(t==0)
        {
            visy[y]=1;
            if(march[y]==-1||dfs(march[y]))
            {
                march[y]=x;
                return 1;
            }
        }
        else if(slack[y]>t)  //不在相等子圖中slack 取最小的
            slack[y]=t;
    }
    return 0;
}

int KM()
{
    int i,j;
    memset(march,-1,sizeof(march));
    memset(ly,0,sizeof(ly));
    for(i=1;i<=nx;i++)            //lx初始化爲與它關聯邊中最大的
        for(j=1,lx[i]=-INF;j<=ny;j++)
            if(w[i][j]>lx[i])
               lx[i]=w[i][j];
    for(int x=1;x<=nx;x++)
    {
        for(i=1;i<=ny;i++)slack[i]=INF;
        while(1)
        {
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(dfs(x))     //若成功(找到了增廣軌),則該點增廣完成,進入下一個點的增廣
                break;  //若失敗(沒有找到增廣軌),則需要改變一些點的標號,使得圖中可行邊的數量增加。
                        //方法爲:將所有在增廣軌中(就是在增廣過程中遍歷到)的X方點的標號全部減去一個常數d,
                        //所有在增廣軌中的Y方點的標號全部加上一個常數d
            int d=INF;
            for(i=1;i<=ny;i++)
                if(!visy[i]&&d>slack[i])
                    d=slack[i];
            for(i=1;i<=nx;i++)
                if(visx[i])
                    lx[i]-=d;
            for(i=1;i<=ny;i++)  //修改頂標後,要把所有不在交錯樹中的Y頂點的slack值都減去d
                if(visy[i])
                    ly[i]+=d;
                else
                    slack[i]-=d;
        }
    }
    int res=0;
    for(i=1;i<=ny;i++)
        if(march[i]>-1)
            res+=w[march[i]][i];
    return res;
}

int ans,chu[maxn],js;
bool use[maxn];
void out()
{
    printf("Best Pairing %d\n",++js);
    for(int i=1;i<=n;i++)
        printf("Supervisor %d with Employee %d\n",i,chu[i]);
}
void solve(int x,int sum)
{
    if(sum<ans)return;
    if(x==n+1){
        out();
        return;
    }
    for(int i=1;i<=n;i++){
        if(use[i]==0){
            use[i]=1;
            chu[x]=i;
            solve(x+1,sum+w[x][i]);
            use[i]=0;
        }
    }
}

int main ()
{
    int i,j,x,T;
    scanf("%d",&T);
    for(int l=1;l<=T;l++){
        scanf("%d",&n);
        nx=ny=n;
        memset(w,0,sizeof(w));
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                scanf("%d",&x);
                w[x][i]-=j-1;
            }
        }
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                scanf("%d",&x);
                w[i][x]-=j-1;
            }
        }
        ans=KM();
        memset(use,0,sizeof(use));
        printf("Data Set %d, Best average difference: %.6f\n",l,-ans*0.5/n);
        js=0;
        solve(1,0);
        printf("\n");
    }
    return 0;
}




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