poj 2400 最小权匹配+匹配输出

Supervisor, Supervisee
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 2055 Accepted: 581

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
题意:老板对员工有一个评价值,评价值越低表示对其好感度越高。员工对老板也有一个评价值,也是评价值越低表示对其好感度越高。求二者最优匹配,使得差异平均值最小。
最小权匹配,然后路径输出(学习于网上)。
权值为正,直接最小权匹配模板代码。
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define inf 9999999
#define maxn 100
int lx[maxn],ly[maxn];
int Match[maxn];
int visx[maxn],visy[maxn];
int w[maxn][maxn];
int slack[maxn];
int y[maxn],count;
int ans,n,m;
bool findPath(int x)
{
    visx[x]=1;
    for(int y=1; y<=n; y++)
    {
        if(visy[y])continue;
        if(w[x][y]==lx[x]+ly[y])
        {
            visy[y]=1;
            if(!Match[y]||findPath(Match[y]))
            {
                Match[y]=x;
                return true;
            }
        }
        else
            slack[y]=min(slack[y],w[x][y]-lx[x]-ly[y]);
    }
    return false;
}
void km()
{
    memset(Match,0,sizeof(Match));
    memset(ly,0,sizeof(ly));
    for(int i=1; i<=n; i++)
    {
        lx[i]=inf;
        for(int j=1; j<=n; j++)
            lx[i]=min(lx[i],w[i][j]);
    }
    for(int x=1; x<=n; x++)
    {
        for(int i=1; i<=n; i++)
            slack[i]=inf;
        while(true)
        {
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(findPath(x))break;
            int tmp=inf;
            for(int i=1; i<=n; i++)
            {
                if(!visy[i])
                {
                    if(tmp>slack[i])
                        tmp=slack[i];
                }
            }
            if(tmp==inf)return ;
            for(int i=1; i<=n; i++)
            {
                if(visx[i])lx[i]+=tmp;
                if(visy[i])ly[i]-=tmp;
            }
        }
    }
}

void dfs(int t,int sum)//dfs输出匹配
{
   int i,j;
   if(sum>ans)return;
   if(t>n)
   {
       if(sum!=ans)return;
       printf("Best Pairing %d\n",++count);
       for(j=1;j<=n;j++)
           printf("Supervisor %d with Employee %d\n",j,y[j]);
       return ;
   }
   for(i=1;i<=n;i++)
   {
       if(!visy[i])
       {
           y[t]=i;
           visy[i]=1;
           dfs(t+1,sum+w[t][i]);
           visy[i]=0;
       }
   }
   return;
}
int main()
{
    int cas,val;
    cin>>cas;
    for(int cc=1; cc<=cas; cc++)
    {
        cin>>n;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
            {
                w[i][j]=0;
            }
        for(int i=1; i<=n; i++)
            for(int j=0; j<n; j++)
            {
                cin>>val;
                w[val][i]+=j;
            }
        for(int i=1; i<=n; i++)
            for(int j=0; j<n; j++)
            {
                cin>>val;
                w[i][val]+=j;
            }
        km();
        ans=0;
        count=0;
        for(int i=1; i<=n; i++)
            if(Match[i])
                ans+=w[Match[i]][i];
        printf("Data Set %d, Best average difference: %.6f\n",cc,ans/(2.0*n));
        memset(visy,0,sizeof(visy));
        dfs(1,0);
        cout<<endl;
    }
    return 0;

}
/*
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
*/

权值为负,转为求最大权值后取反模板代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define inf 9999999
#define maxn 105
int lx[maxn],ly[maxn];
int Match[maxn];
int visx[maxn],visy[maxn];
int w[maxn][maxn];
int slack[maxn];
int y[maxn];
int link[maxn],count;
int ans,n;
bool findPath(int x)
{
    visx[x]=1;
    for(int y=1; y<=n; y++)
    {
        if(visy[y])continue;
        if(w[x][y]==lx[x]+ly[y])
        {
            visy[y]=1;
            if(!Match[y]||findPath(Match[y]))
            {
                Match[y]=x;
                return true;
            }
        }
        else
            slack[y]=min(slack[y],lx[x]+ly[y]-w[x][y]);
    }
    return false;
}
void km()
{
    memset(Match,0,sizeof(Match));
    memset(ly,0,sizeof(ly));
    for(int i=1; i<=n; i++)
    {
        lx[i]=-inf;
        for(int j=1; j<=n; j++)
            lx[i]=max(lx[i],w[i][j]);
    }
    for(int x=1; x<=n; x++)
    {
        for(int i=1; i<=n; i++)
            slack[i]=inf;
        while(true)
        {
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(findPath(x))break;
            int tmp=inf;
            for(int i=1; i<=n; i++)
            {
                if(!visy[i])
                {
                    if(tmp>slack[i])
                        tmp=slack[i];
                }
            }
            if(tmp==inf)return ;
            for(int i=1; i<=n; i++)
            {
                if(visx[i])lx[i]-=tmp;
                if(visy[i])ly[i]+=tmp;
            }
        }
    }
}


void dfs(int dep, int sum)     //  深搜构造所有能达到最大值的匹配情况。
{
    if(sum>ans) return;
    if(dep>n)
    {
        if(sum != ans) return;
        printf("Best Pairing %d\n", count ++);
        for(int i = 1; i <= n; i ++)
            printf("Supervisor %d with Employee %d\n", i, link[i]);
    }
    else
    {
        for(int i = 1; i <= n; i ++)
            if(!y[i])
            {
                y[i]=1;
                link[dep] = i;
                dfs(dep+1, sum-w[dep][i]);
                y[i]=0;
            }
    }
}
int main()
{
    int cas,val;
    cin>>cas;
    for(int cc=1; cc<=cas; cc++)
    {
        cin>>n;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
            {
                w[i][j]=0;
            }
        for(int i=1; i<=n; i++)
            for(int j=0; j<n; j++)
            {
                cin>>val;
                w[val][i]-=j;
            }
        for(int i=1; i<=n; i++)
            for(int j=0; j<n; j++)
            {
                cin>>val;
                w[i][val]-=j;
            }
        km();
        ans=0;
        count=1;
        for(int i=1; i<=n; i++)
            if(Match[i])
                ans-=w[Match[i]][i];
        //cout<<ans<<endl;
        printf("Data Set %d, Best average difference: %.6f\n",cc,ans/(2.0*n));
        memset(y,0,sizeof(y));
        dfs(1,0);
        cout<<endl;
    }
    return 0;

}
/*
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
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值