POJ2198-二分图最佳匹配

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>

using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define DBG printf("this is a input\n")
#define first fi
#define second se
#define mk(a, b) make_pair(a,b)
int n , m;
int edge[120][120],m_cnt,h_cnt;
int cx[120],cy[120],fa[120],usex[120],usey[120];
struct node
{
    int x , y;
}man[120],hourse[120];

bool find(int root)
{
    usex[root] = 1;
    for(int i = 1 ; i < h_cnt ; i ++)
    {
        if(usey[i]== 0 && (cx[root]+cy[i] == edge[root][i])) //判断是否可以连线(标杆值之和等于边权,代表存在边)
        {
            usey[i] = 1;
            if(fa[i] == 0 || find(fa[i]))
            {
                fa[i] = root;
                return true;
            }
        }
    }
    return false;
}
int km()
{
    for(int i = 1 ; i < m_cnt ; i ++)
    {
        while(1)
        {
            int minn = -INF;
            mem(usex,0),mem(usey,0);
            if(find(i)) //匈牙利算法寻找是否存在增广路
                break;
            for(int j = 1 ; j < m_cnt ; j ++) //寻找用于修改标杆的最小值
            {
                if(usex[j]) //A集合中匹配过的点 
                {
                    for (int k = 1; k < h_cnt; k++)
                    {
                        if(!usey[k])//b集合中未匹配过的点
                            minn = min(minn,cx[j]+cy[k]-edge[j][k]);
                    }
                }
            }
            //修改标杆
            for(int j = 1 ; j < m_cnt ; j ++)
                if(usex[j]) cx[j] -= minn;
            for(int j = 1 ; j < h_cnt ; j ++)
                if(usey[j]) cy[j] += minn;
        }
    }
    int pp = 0;
    for(int i = 1 ; i < h_cnt ; i ++)
        pp += edge[fa[i]][i];
    return pp;
}
int main()
{
    while(scanf("%d %d",&n , &m) != EOF)
    {
        if(n == 0 && m == 0)
            break;
        m_cnt = 1, h_cnt = 1;
        mem(cy,0),mem(cx,0),mem(edge,0),mem(fa,0);
        char ch[105];
        for(int i = 1 ; i <= n ; i ++)
        {
            scanf("%s",ch);
            for (int j = 0; j < m; j++)
            {
                if(ch[j] == 'm')
                {
                    man[m_cnt].x = i;
                    man[m_cnt].y = j+1;
                    m_cnt ++;
                }
                if(ch[j] == 'H')
                {
                    hourse[h_cnt].x = i;
                    hourse[h_cnt].y = j+1;
                    h_cnt ++;
                }
            }
        }
        for(int i = 1 ; i < m_cnt ; i ++) {
            int maxn = -INF;
            for (int j = 1; j < h_cnt; j++) {
                edge[i][j] = -(abs(man[i].x - hourse[j].x) + abs(man[i].y - hourse[j].y));
                maxn = max(edge[i][j],maxn);
            }
            cx[i] = maxn;
        }
        int ans = km();
        printf("%d\n",-ans);
    }
    return 0;
}

模版二:

//#define LOCAL
#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define p_queue priority_queue
#define eps 1e-8
ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a % b);
}

ll lcm(ll a, ll b) {
    return a / gcd(a, b) * b;
}

int n , m;
struct node{
    double x , y;
}white[105], black[105];
double Dis(int i , int j)
{
    return sqrt((white[i].x - black[j].x)*(white[i].x - black[j].x) + (white[i].y - black[j].y)*(white[i].y - black[j].y));
}
double dis[105][105];
double la[105], lb[105];
int va[105] , vb[105];
int match[105];
double delta, upd[105];
bool dfs(int x)
{
    va[x] = 1;
    for(int y = 1 ; y <= n ; y ++)
    {
        if(!vb[y])
        {
            if(fabs(la[x] + lb[y] - dis[x][y]) < 1e-10)
            {
                vb[y] = 1;
                if(!match[y] || dfs(match[y]))
                {
                    match[y] = x;
                    return true;
                }
            }
            else
                upd[y] = min(upd[y], la[x] + lb[y] - dis[x][y]);
        }
    }
    return false;
}
void KM()
{
    for(int i = 1 ; i <= n ; i ++)
    {
        la[i] = - DNF;
        lb[i] = 0;
        for(int j = 1 ; j <= n ; j ++)
            la[i] = max(la[i],dis[i][j]);
    }
    for(int i = 1 ; i <= n ; i ++)
    {
        while(true)
        {
            mem(va,0);
            mem(vb,0);
            delta = DNF;
            for(int j = 1 ; j <= n ; j ++) upd[j] = DNF;
            if(dfs(i)) break;
            for(int j = 1 ;  j <= n ; j ++)
                if(!vb[j]) delta = min(delta , upd[j]);
            for(int j = 1 ; j <= n  ; j ++){
                if(va[j]) la[j] -= delta;
                if(vb[j]) lb[j] += delta;
            }
        }
    }
}
int main(void)
{
#ifdef LOCAL
    freopen("data.in", "r", stdin);
    freopen("odata.out", "w", stdout);
#endif
    cin>>n;
    for(int i = 1 ; i <= n ; i ++)
        cin>>black[i].x>>black[i].y;
    for(int i = 1 ; i <= n ; i ++)
        cin>>white[i].x>>white[i].y;
    for(int i = 1 ; i <= n ; i ++)
        for(int j = 1 ; j <= n ; j ++)
            dis[i][j] = -Dis(i,j);
    KM();
    for(int i = 1 ; i <= n ; i ++)
        cout<<match[i]<<endl;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值