poj 2400(最小权匹配)

题意:给出雇主对雇员的满意度和雇员对雇主的满意度,分数越低代表评价越高,求给出最优匹配方案。当有多种最优匹配,全部输出!

思路:典型的最小权匹配,km算法求解

View Code
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 #define inf 0x3f3f3f3f
  7 #define N 111
  8 int net[N][N],x[N],y[N],lx[N],ly[N],link[N],b[N],like[N];
  9 int n,sum,d,cnt;
 10 bool km_dfs(int u)
 11 {
 12     x[u]=1;
 13     for(int i=1;i<=n;i++)
 14     {
 15         if(y[i])continue;
 16         int t=lx[u]+ly[i]-net[u][i];
 17         if(t==0)
 18         {
 19             y[i]=1;
 20             if(!link[i]||km_dfs(link[i]))
 21             {
 22                 link[i]=u;
 23                 return true;
 24             }
 25         }
 26         else d=min(d,t);
 27     }
 28     return false;
 29 }
 30 double km()
 31 {
 32     memset(lx,0,sizeof(lx));
 33     memset(ly,0,sizeof(ly));
 34     memset(link,0,sizeof(link));
 35     for(int i=1;i<=n;i++)
 36     {
 37         while(1){
 38             d=inf;
 39             memset(x,0,sizeof(x));
 40             memset(y,0,sizeof(y));
 41             if(km_dfs(i))break;
 42             for(int j=1;j<=n;j++)
 43             {
 44                 if(x[j])lx[j]-=d;
 45                 if(y[j])ly[j]+=d;
 46             }
 47         }
 48     }
 49     sum=0;
 50     for(int i=1;i<=n;i++)
 51     {
 52         sum-=lx[i]+ly[i];
 53     }
 54     return 1.0*sum/(n*2);
 55 }
 56 void dfs(int step,int total)
 57 {
 58     if(total>sum)return ;
 59     if(step==n+1)
 60     {
 61         printf("Best Pairing %d\n",cnt++);
 62         for(int i=1;i<=n;i++)
 63         printf("Supervisor %d with Employee %d\n",i,like[i]);
 64         return ;
 65     }
 66     for(int i=1;i<=n;i++)
 67     {
 68         if(!b[i]){
 69             b[i]=1;
 70             like[step]=i;
 71             dfs(step+1,total-net[step][i]);
 72             b[i]=0;
 73         }
 74     }
 75 }
 76 int main()
 77 {
 78     int ca;
 79     scanf("%d",&ca);
 80     int cas=1;
 81     while(ca--)
 82     {
 83         int x;
 84         cnt=1;
 85         memset(net,0,sizeof(net));
 86         scanf("%d",&n);
 87         for(int i=1;i<=n;i++)
 88         {
 89             for(int j=1;j<=n;j++)
 90             {
 91                 scanf("%d",&x);
 92                 net[x][i]-=j;
 93             }
 94         }
 95         for(int i=1;i<=n;i++)
 96         {
 97             for(int j=1;j<=n;j++)
 98             {
 99                 scanf("%d",&x);
100                 net[i][x]-=j;//最小权匹配取负数
101             }
102         }
103         double ans=km();
104         printf("Data Set %d, Best average difference: %.6lf\n",cas++,ans-1);
105         memset(b,0,sizeof(b));
106         dfs(1,0);
107         printf("\n");
108     }
109     return 0;
110 }

 

转载于:https://www.cnblogs.com/huangriq/archive/2012/05/12/2497667.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值