uva 1411(二分图最小权)

Young naturalist Bill studies ants in school. His ants feed on
plant-louses that live on apple trees. Each ant colony needs
its own apple tree to feed itself.
Bill has a map with coordinates of n ant colonies and n
apple trees. He knows that ants travel from their colony to
their feeding places and back using chemically tagged routes.
The routes cannot intersect each other or ants will get confused
and get to the wrong colony or tree, thus spurring a war
between colonies.
Bill would like to connect each ant colony to a single apple
tree so that all n routes are non-intersecting straight lines. In
this problem such connection is always possible. Your task is
to write a program that finds such connection.
On the picture ant colonies are denoted by empty circles and apple trees are denoted by filled circles.
One possible connection is denoted by lines.
Input
Input has several dataset. The first line of each dataset contains a single integer number n (1 ≤ n ≤ 100)
— the number of ant colonies and apple trees. It is followed by n lines describing n ant colonies, followed
by n lines describing n apple trees. Each ant colony and apple tree is described by a pair of integer
coordinates x and y (−10000 ≤ x, y ≤ 10000) on a Cartesian plane. All ant colonies and apple trees
occupy distinct points on a plane. No three points are on the same line.
Output
For each dataset, write to the output file n lines with one integer number on each line. The number
written on i-th line denotes the number (from 1 to n) of the apple tree that is connected to the i-th
ant colony.
Print a blank line between datasets.
Sample Input
5
-42 58
44 86
7 28
99 34
-13 -59
-47 -44
86 74
68 -75
-68 60
99 -60
Sample Output
4
2
1
5

就是 求二分图最小权,就是转为负数求最大权,还有不知道为啥要用 w[j][i] 而不是w[i][j]

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN = 305;
const int INF = 0x3f3f3f3f;

double love[MAXN][MAXN];   // 记录每个妹子和每个男生的好感度
double ex_girl[MAXN];      // 每个妹子的期望值
double ex_boy[MAXN];       // 每个男生的期望值
bool vis_girl[MAXN];    // 记录每一轮匹配匹配过的女生
bool vis_boy[MAXN];     // 记录每一轮匹配匹配过的男生
int match[MAXN];        // 记录每个男生匹配到的妹子 如果没有则为-1
double slack[MAXN];        // 记录每个汉子如果能被妹子倾心最少还需要多少期望值
int xx1[MAXN],xx2[MAXN],yy1[MAXN],yy2[MAXN];


int N;

double dist(int x1,int y1,int x2,int y2)
{
    return sqrt((double)(x1-x2)*(x1-x2)+(double)(y1-y2)*(y1-y2));
}
bool dfs(int girl)
{
    vis_girl[girl] = true;

    for (int boy = 0; boy < N; ++boy) {

        if (vis_boy[boy]) continue; // 每一轮匹配 每个男生只尝试一次

        double gap = ex_girl[girl] + ex_boy[boy] - love[girl][boy];

        if (gap <1e-6) {  // 如果符合要求
            vis_boy[boy] = true;
            if (match[boy] == -1 || dfs( match[boy] )) {    // 找到一个没有匹配的男生 或者该男生的妹子可以找到其他人
                match[boy] = girl;
                return true;
            }
        } else {
            slack[boy] = min(slack[boy], gap);  // slack 可以理解为该男生要得到女生的倾心 还需多少期望值 取最小值 备胎的样子【捂脸
        }
    }

    return false;
}

double KM()
{
    memset(match, -1, sizeof match);    // 初始每个男生都没有匹配的女生
    memset(ex_boy, 0, sizeof ex_boy);   // 初始每个男生的期望值为0

    // 每个女生的初始期望值是与她相连的男生最大的好感度
    for (int i = 0; i < N; ++i) {
        ex_girl[i] = love[i][0];
        for (int j = 1; j < N; ++j) {
            ex_girl[i] = max(ex_girl[i], love[i][j]);
        }
    }

    // 尝试为每一个女生解决归宿问题
    for (int i = 0; i < N; ++i) {

        fill(slack, slack + N, INF);    // 因为要取最小值 初始化为无穷大

        while (1) {
            // 为每个女生解决归宿问题的方法是 :如果找不到就降低期望值,直到找到为止

            // 记录每轮匹配中男生女生是否被尝试匹配过
            memset(vis_girl, false, sizeof vis_girl);
            memset(vis_boy, false, sizeof vis_boy);

            if (dfs(i)) break;  // 找到归宿 退出

            // 如果不能找到 就降低期望值
            // 最小可降低的期望值
            double d = INF;
            for (int j = 0; j < N; ++j)
                if (!vis_boy[j]) d = min(d, slack[j]);

            for (int j = 0; j < N; ++j) {
                // 所有访问过的女生降低期望值
                if (vis_girl[j]) ex_girl[j] -= d;

                // 所有访问过的男生增加期望值
                if (vis_boy[j]) ex_boy[j] += d;
                // 没有访问过的boy 因为girl们的期望值降低,距离得到女生倾心又进了一步!
                else slack[j] -= d;
            }
        }
    }

    // 匹配完成 求出所有配对的好感度的和
}




int main()
{
    int kase=0;
    while (~scanf("%d", &N)) {
            if(kase)
            printf("\n");
            for(int i=0;i<N;i++)
            scanf("%d%d",&xx1[i],&yy1[i]);
            for(int i=0;i<N;i++)
                scanf("%d%d",&xx2[i],&yy2[i]);
            for(int i=0;i<N;i++)
            {
                for(int j=0;j<N;j++)
                {
                    love[j][i]=-dist(xx1[i],yy1[i],xx2[j],yy2[j]);
                }
            }
            KM();
            for(int i=0;i<N;i++)
            {
                printf("%d\n",match[i]+1);
            }
            kase=1;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值