P6577 【模板】二分图最大权完美匹配

P6577 【模板】二分图最大权完美匹配
P6577 【模板】二分图最大权完美匹配_第1张图片
①、进阶指南上说他的KM算法的时间复杂度是O(N3)的,其实分析一下,就可以发现,它的时间复杂度其实是O(N4)的,这题过不去。
只能过去四个点。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define llu unsigned ll
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const int maxn=510;
ll w[maxn][maxn];
ll la[maxn],lb[maxn];
bool va[maxn],vb[maxn];
int match[maxn],n,m;
ll delta;

bool dfs(int x)
{
    va[x]=1;
    for(int y=1;y<=n;y++)
    {
        if(!vb[y])
            if(la[x]+lb[y]-w[x][y]==0)
            {
                vb[y]=1;
                if(!match[y]||dfs(match[y]))
                {
                    match[y]=x;
                    return true;
                }
            }
        else delta = min(delta,la[x]+lb[y]-w[x][y]);

    }
    return false;
}

ll KM(void)
{
    for(int i=1;i<=n;i++)
    {
        la[i]=-lnf;
        lb[i]=0;
        for(int j=1;j<=n;j++)
            la[i]=max(la[i],w[i][j]);
    }

    for(int i=1;i<=n;i++)
    {
        while(true)
        {
            for(int j=1;j<=n;j++)
            {
                va[j]=vb[j]=false;
            }
            delta = lnf;
            if(dfs(i)) break;

            for(int j=1;j<=n;j++)
            {
                if(va[j]) la[j]-=delta;
                if(vb[j]) lb[j]+=delta;
            }
        }
    }

    ll ans=0;
    for(int i=1;i<=n;i++)
        ans+=w[match[i]][i];

    return ans;
}

int main(void)
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            w[i][j]=-lnf;
    int x,y,z;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        w[x][y]=max(w[x][y],1ll*z);
    }
    printf("%lld\n",KM());
    for(int i=1;i<=n;i++)
        printf("%lld ",match[i]);
    putchar('\n');
    return 0;
}

②、之前还存了一个完全图优化的板子,过了五个点,看来有一个是完全图。
不过这两个板子应该都是加算法,最坏情况到了O(N4

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define llu unsigned ll
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const int maxn=510;
ll w[maxn][maxn];
ll la[maxn],lb[maxn],d[maxn];
bool va[maxn],vb[maxn];
int match[maxn],n,m;

bool dfs(int x)
{
    va[x]=1;
    for(int y=1;y<=n;y++)
    {
        if(!vb[y])
            if(la[x]+lb[y]-w[x][y]==0)
            {
                vb[y]=1;
                if(!match[y]||dfs(match[y]))
                {
                    match[y]=x;
                    return true;
                }
            }
        else d[y] = min(d[y],la[x]+lb[y]-w[x][y]);

    }
    return false;
}

ll KM(void)
{
    for(int i=1;i<=n;i++)
    {
        la[i]=-lnf;
        lb[i]=0;
        for(int j=1;j<=n;j++)
            la[i]=max(la[i],w[i][j]);
    }

    for(int i=1;i<=n;i++)
    {
        while(true)
        {
            for(int j=1;j<=n;j++)
            {
                va[j]=vb[j]=false;
                d[j]=lnf;
            }
            if(dfs(i)) break;
            ll c=lnf;
            for(int j=1;j<=n;j++)
                if(!vb[j]) c=min(c,d[j]);
            for(int j=1;j<=n;j++)
            {
                if(va[j]) la[j]-=c;
                if(vb[j]) lb[j]+=c;
            }
        }
    }

    ll ans=0;
    for(int i=1;i<=n;i++)
        ans+=w[match[i]][i];

    return ans;
}

int main(void)
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            w[i][j]=-lnf;
    int x,y,z;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        w[x][y]=max(w[x][y],1ll*z);
    }
    printf("%lld\n",KM());
    for(int i=1;i<=n;i++)
        printf("%lld ",match[i]);
    putchar('\n');
    return 0;
}

③、于是我们找到了算法复杂度为O(N3)的bfs写法。
其实这个算法在数据随机下是O(N 3),但是可以被卡成O(N4
但是因为这个题大数据下随机,所以可以通过这个题。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define llu unsigned ll
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const int maxn=510;
ll w[maxn][maxn];
ll la[maxn],lb[maxn];
ll p[maxn],c[maxn];
bool vb[maxn];
int match[maxn],n,m;

void bfs(int x)
{
    int a,y=0,yy=0;
    ll d;
    for(int i=1;i<=n;i++)
        p[i]=0,c[i]=lnf;
    match[y]=x;
    do{
        a=match[y],d=lnf,vb[y]=true;
        for(int b=1;b<=n;b++)
        {
            if(!vb[b])
            {
                if(c[b]>la[a]+lb[b]-w[a][b])
                    c[b]=la[a]+lb[b]-w[a][b],p[b]=y;
                if(c[b]<d) d=c[b],yy=b;
            }
        }
        for(int b=0;b<=n;b++)
        {
            if(vb[b]) la[match[b]]-=d,lb[b]+=d;
            else c[b]-=d;
        }
        y=yy;
    }while(match[y]);

    while(y) match[y]=match[p[y]],y=p[y];
}

ll KM(void)
{
    for(int i=1;i<=n;i++)
        la[i]=lb[i]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++) vb[j]=false;
        bfs(i);
    }
    ll ans=0;
    for(int i=1;i<=n;i++)
        ans+=w[match[i]][i];

    return ans;
}

int main(void)
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            w[i][j]=-lnf;
    int x,y,z;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        w[x][y]=max(w[x][y],1ll*z);
    }
    printf("%lld\n",KM());
    for(int i=1;i<=n;i++)
        printf("%lld ",match[i]);
    putchar('\n');
    return 0;
}

你可能感兴趣的:(图论基本算法,网络流基本算法)