POJ3686-KM匹配模板题

来源:互联网 发布:玻璃扯旗鱼淘宝 编辑:程序博客网 时间:2024/06/05 02:21
#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int NN=2550;const int INF=0x3fffffff;int n,m,lx[NN],ly[NN],w[NN][NN],a[NN][NN],match[NN],slack[NN];bool vx[NN],vy[NN];void init(){    scanf("%d%d",&n,&m);    for (int i=0; i<n; i++)      for (int j=0; j<m; j++) scanf("%d",&a[i][j]);    for (int i=0; i<n; i++)      for (int j=0; j<m; j++)        for (int k=1; k<=n; k++)        {            w[i][j+(k-1)*m]=-a[i][j]*k;        }    m=n*m;}bool dfs(int u){    vx[u]=true;    for (int v=0; v<m; v++)    {        if (vy[v]) continue;        int t=lx[u]+ly[v]-w[u][v];        if (t==0)        {            vy[v]=true;            if (match[v]==-1 || dfs(match[v]))            {                match[v]=u;                return true;            }        }        else if (slack[v]>t) slack[v]=t;    }    return false;}double KM(){    memset(match,-1,sizeof(match));    memset(lx,0,sizeof(lx));    memset(ly,0,sizeof(ly));    for (int i=0; i<n; i++)        for (int j=0; j<m; j++) if (w[i][j]>lx[i]) lx[i]=w[i][j];    for (int x=0; x<n; x++)    {        for (int i=0; i<m; i++) slack[i]=INF;        while (1)        {            memset(vx,0,sizeof(vx));            memset(vy,0,sizeof(vy));            if (dfs(x)) break;            int d=INF;            for (int i=0; i<m; i++)                if (!vy[i] && d>slack[i]) d=slack[i];            for (int i=0; i<n; i++) if (vx[i]) lx[i]-=d;            for (int i=0; i<m; i++) if (vy[i]) ly[i]+=d; else slack[i]-=d;        }    }    double ret=0;    for (int i=0; i<m; i++)    {        if (match[i]!=-1) ret+=w[match[i]][i];    }    return ret;}int main(){    int cas;    scanf("%d",&cas);    while (cas--)    {        init();        printf("%.6f\n",-KM()/(n*1.0));    }    return 0;}

原创粉丝点击