带权二分图——KM算法hdu2255 poj3565

进阶指南的板子好像有点问题。。交到hdu上会T

需要了解的一些概念:

  交错树,顶标,修改量

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 99999999
#define maxn 305
 
int lx[maxn],ly[maxn];//顶标
int Match[maxn];//记录匹配值
int visx[maxn],visy[maxn];
int w[maxn][maxn];//权值
int slack[maxn];//slack为修改量
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(lx,0,sizeof(lx));
    memset(ly,0,sizeof(ly));
    for(int i=1; i<=n; i++)
        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(1){
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(findPath(x))break;//直到x找到一个匹配点时退出循环 
            //如果没找到匹配点(增广失败),那么找最小修改量, 
            int tmp=INF;
            for(int i=1;i<=n;i++){
                if(!visy[i]){
                    if(tmp>slack[i])
                    tmp=slack[i];
                }
            }
            //更新交错树中的顶标 
            for(int i=1; i<=n; i++){
                if(visx[i]) lx[i]-=tmp;
                if(visy[i]) ly[i]+=tmp;else slack[i]-=tmp;
            }
        }
    }
}
int main(){
    while(scanf("%d",&n)!=EOF){
        ans=0;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                scanf("%d",&w[i][j]);
        km();
        for(int i=1; i<=n; i++)
            ans+=w[Match[i]][i];
        printf("%d\n",ans);
    }
    return 0;
}

 

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 110;
const double INF = 0xffffffffffff;
const double eps = 1e-6;
 
struct Node
{
    double x,y;
}Dot1[MAXN],Dot2[MAXN];
 
double Dist(Node a,Node b)
{
    return -sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
 
int N,NX,NY;
double Map[MAXN][MAXN];
int link[MAXN];
double lx[MAXN],ly[MAXN],slack[MAXN];
int visx[MAXN],visy[MAXN];
 
int FindPath(int u)
{
    visx[u] = 1;
    for(int i = 1; i <= NY; ++i)
    {
        if(visy[i])
            continue;
        double temp = lx[u] + ly[i] - Map[u][i];
        if(fabs(temp) <= eps)
        {
            visy[i] = 1;
            if(link[i] == -1 || FindPath(link[i]))
            {
                link[i] = u;
                return 1;
            }
        }
        else
        {
            if(slack[i] > temp)
                slack[i] = temp;
        }
    }
    return 0;
}
 
void KM()
{
    memset(lx,0,sizeof(lx));
    memset(ly,0,sizeof(ly));
    memset(link,-1,sizeof(link));
    for(int i = 1; i <= NX; ++i) 
    {
    lx[i] = -INF;
        for(int j = 1; j <= NY; ++j)
            if(Map[i][j] > lx[i])
                lx[i] = Map[i][j];
    }
 
    for(int i = 1; i <= NX; ++i)
    {
        for(int j = 1; j <= NY; ++j)
            slack[j] = INF;
        while(1)
        {
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(FindPath(i))
                break;
            double d = INF;
            for(int j = 1; j <= NY; ++j)
                if(!visy[j] && d > slack[j])
                    d = slack[j];
            for(int j = 1; j <= NX; ++j)
                if(visx[j])
                    lx[j] -= d;
            for(int j = 1; j <= NY; ++j)
            {
                if(visy[j])
                    ly[j] += d;
                else
                    slack[j] -= d;
            }
        }
    }
}
 
int main()
{
    int N;
    while(~scanf("%d",&N))
    {
        memset(Map,0,sizeof(Map));
        for(int i = 1; i <= N; ++i)
            scanf("%lf%lf",&Dot1[i].x,&Dot1[i].y);
        for(int i = 1; i <= N; ++i)
            scanf("%lf%lf",&Dot2[i].x,&Dot2[i].y);
 
        for(int i = 1; i <= N; ++i)
            for(int j = 1; j <= N; ++j)
                Map[i][j] = Dist(Dot1[i],Dot2[j]);
 
        NX = NY = N;
        KM();
        for(int i = 1; i <= N; ++i)
        {
            for(int j = 1; j <= N; ++j)
            {
                if(link[j] == i)
                {
                    printf("%d\n",j);
                    break;
                }
            }
        }
    }
 
    return 0;
}

 

posted on 2019-05-19 15:41  zsben  阅读(171)  评论(0编辑  收藏  举报

导航