ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

3739. 【TJOI2014】匹配(match)

2022-01-14 20:32:26  阅读:156  来源: 互联网

标签:include 匹配 int flow 男孩 3739 TJOI2014 now match


Description

有 \(N\) 个单身的男孩和 \(N\) 个单身女孩,男孩 \(i\) 和女孩 \(j\) 在一起得到的幸福值为 \(H_{i,j}\) 。一个匹配即对这 \(N\) 个男孩女孩的安排:每个男孩恰好有一个女朋友, 每个女孩恰好有一个男朋友。

一个匹配的幸福值即这 \(N\) 对男女朋友的幸福值的和。经典的问题是计算幸福值最大的匹配,即完美匹配。然而完美匹配有时候并不唯一,你需要计算,对于所有的完美匹配,其交集是什么。

Solution

这题是经典的费用流/带权网络流,我写的是费用流。

先用最大费用最大流的模板求出完美匹配。

题目要求的交集就是指那些一定在完美匹配中的边,一种朴素的想法是枚举每条男孩女孩间的边,将它删去,然后再跑最大费用最大流,看两次的结果有无变化,若变小则说明删去的那条边是一定在残量网络中的。

但这种做法会超时,考虑优化,注意到在第一次跑完费用流后,此时每个男孩有且仅有一条边连向女孩,而其他的所有边可以确定不在交集中,因为已经至少有一种方法不走它们了。

那么我们把这些边找出来,将每条边一一删去,然后再跑费用流,可以将时间复杂度下降一个数量级。

Code

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100
#define inf 2147483647
using namespace std;
struct node
{
    int to,next,flow,val,head,flag;
}a[N*N*4];
deque<int> q;
int n,x,S,T,tot=1,ans,sum,dis[N<<1],c[N],cur[N<<1];
bool bj[N<<1],bz[N<<1],bb[N*N*4];
void add(int x,int y,int fl,int va)
{
    a[++tot].to=y;
    a[tot].flow=fl;
    a[tot].val=va;
    a[tot].next=a[x].head;
    a[x].head=tot;
}
bool check()
{
    for (int i=1;i<=2*n+2;++i)
        dis[i]=-inf,bj[i]=false;
    q.push_back(T);
    dis[T]=0;
    while (!q.empty())
    {
        int x=q.front();q.pop_front();
        for (int i=a[x].head;i;i=a[i].next)
        {
            if (bb[i]) continue;
            int y=a[i].to;
            if (a[i].flag) continue;
            if (a[i^1].flow&&dis[y]<dis[x]-a[i].val)
            {
                dis[y]=dis[x]-a[i].val;
                if (!bj[y])
                {
                    bj[y]=true;
                    if (q.empty()||dis[y]<dis[q.front()]) q.push_back(y);
                    else q.push_front(y);
                }
            }
        }
        bj[x]=false;
    }
    return dis[S]>-inf;
}
int calc(int now,int flow)
{
    if (now==T) return flow;
    bz[now]=true;
    int fw=0;
    for (int i=cur[now];i;i=a[i].next)
    {
        if (bb[i]) continue;
        int v=a[i].to;
        if (!bz[v]&&dis[now]==dis[v]+a[i].val&&a[i].flow)
        {
            int f=calc(v,min(flow,a[i].flow));
            if (f)
            {
                a[i].flow-=f;
                a[i^1].flow+=f;
                fw+=f;
                flow-=f;
                cur[now]=i;
                if (!flow) break;
            }
        }
    }
    return fw;
}
int fyl()
{
    int res=0;
    while (check())
    {
        bz[T]=true;
        while (bz[T])
        {
            for (int i=1;i<=2*n+2;++i)
                cur[i]=a[i].head,bz[i]=false;
            res+=dis[S]*calc(S,inf);
        }
    }
    return res;
}
void beback()
{
    for (int i=a[S].head;i;i=a[i].next)
        a[i].flow=1;
    for (int i=1;i<=n;++i)
    {
        for (int j=a[i].head;j;j=a[j].next)
        {
            if (a[j].to==S) a[j].flow=0;
            if (a[j].to>n&&a[j].to<=2*n) a[j].flow=1;
        }
    }
    for (int i=n+1;i<=2*n;++i)
    {
        for (int j=a[i].head;j;j=a[j].next)
        {
            if (a[j].to==T) a[j].flow=1;
            if (a[j].to<=n) a[j].flow=0;
        }
    }
    for (int i=a[T].head;i;i=a[i].next) 
        a[i].flow=0;
}
int main()
{
    freopen("match.in","r",stdin);
    freopen("match.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
        {
            scanf("%d",&x);
            add(i,j+n,1,x);
            add(j+n,i,0,-x);
        }
    S=n*2+1;T=n*2+2;
    for (int i=1;i<=n;++i)
    {
        add(S,i,1,0);add(i,S,0,0);
        add(i+n,T,1,0);add(T,i+n,0,0);
    }
    ans=fyl();
    printf("%d\n",ans);
    sum=ans;
    for (int i=1;i<=n;++i)
    {
        for (int j=a[i].head;j;j=a[j].next)
        {
            if (a[j].to>n&&a[j].to<=2*n) 
            {
                if (!a[j].flow) 
                {
                    c[i]=j;
                    break;
                }
            }
        }
    }
    for (int i=1;i<=n;++i)
    {
        beback();
        bb[c[i]]=true;
        bb[c[i]^1]=true;
        ans=fyl();
        if (ans<sum) printf("%d %d\n",i,a[c[i]].to-n);
        bb[c[i]]=false;
        bb[c[i]^1]=false;
    }
    return 0;
}

标签:include,匹配,int,flow,男孩,3739,TJOI2014,now,match
来源: https://www.cnblogs.com/Livingston/p/15803429.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有