匹配问题汇总

JOJ 2662: 采购方案 (二分答案+多重匹配)

CCST@JLU 要举办这次的程序设计大赛。为了节省开支,在各方面都得考虑仔细,比赛场地布置也不例外。在布置场地时,需要为每台电脑提供电源,由于电脑和电源的位置已经固定,所以要采购一些电源线来连接电脑和电源。kkk在采购时发现,购买相同数量的等长电源线总比购买长度不一的电源线要便宜很多(虽然电源线的价格和长度成正比,却不影响这个规律:)),所以kkk决定购买相同长度的电源线来布置场地。kkk想节省开支,你能帮助他么?

 

题解 :二分答案 + 多重匹配,枚举答案,对小于等于枚举数的边加入到网络中看是否可行,可行就继续找比它小的解 , 不可行就找大一点的解。

 

多重匹配流的构图,很好想 , 将可多词匹配的点与源汇的连边的权值更改成可匹配的次数即可。

#include <cstdio>
#include <cstring>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)

const int maxn=800;
const int inf = 1<<28;
const int s=0 ;
struct Edge {
    int v,next,w;
}edge[maxn*maxn];
int head[maxn],cnt;//for sap

void addedge(int u , int v , int w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].v=u;
    edge[cnt].w=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
int n,m,cc;
///
int sap(int t)
{
    int pre[maxn],cur[maxn];
    int dis[maxn],gap[maxn];
    int flow=0 , aug=inf ,u;
    bool flag;
    for (int i=0 ; i<=t ; ++i)
    {
        cur[i]=head[i];
        gap[i]=dis[i]=0;
    }
    gap[s]=t+1;
    u=pre[s]=s;
    while (dis[s]<=t)
    {
          flag=0 ;
          for (int &j=cur[u] ; ~j ; j=edge[j].next)
          {
              int v=edge[j].v;
              if (edge[j].w>0 && dis[u]==dis[v]+1)
              {
                   flag=1;
                   if(edge[j].w<aug)aug=edge[j].w;
                   pre[v]=u;
                   u=v;
                   if (u==t)
                   {
                       flow+=aug;
                       while (u!=s)
                       {
                             u=pre[u];
                             edge[cur[u]].w-=aug;
                             edge[cur[u]^1].w+=aug;
                       }
                       aug=inf;
                   }
                   break;
              }
          }
          if (flag)continue ;
          int mindis=t+1;
          for (int j=head[u]; ~j ; j=edge[j].next)
          {
              int v=edge[j].v;
              if (edge[j].w>0 && dis[v]<mindis)
              {
                 mindis=dis[v];
                 cur[u]=j;
              }

          }
          if(--gap[dis[u]]==0)break;
          gap[dis[u]=mindis+1]++;
          u=pre[u];
    }
    return flow;
}


int map[maxn][maxn];
int c[maxn];

int main ()
{
    int cas;
    scanf("%d",&cas);
    while (cas--)
    {
        scanf("%d%d%d",&n,&m,&cc);
        for (int i=0 ; i<n ; ++i)
        {
            for (int j=0 ; j<m ; ++j)
            {
                scanf("%d",map[i]+j);
            }
        }
        int sum=0;
        for (int i=0 ; i<m ; ++i)
        {
            scanf("%d",c+i);
            sum+=c[i];
        }
        if(sum<n){puts("-1"); continue;}
        int ans=inf;
        int l=0,r=10000;
        ///
        while (l<=r)
        {
            int mid=(l+r)>>1;
            memset (head , -1 , sizeof(head));
            cnt=0;
            for (int i=0 ; i<n ; ++i)
            {
                addedge (0 , i+1 , 1);
                for (int j=0 ; j<m ; ++j)
                {
                    if(map[i][j]<=mid)
                    {
                        addedge(i+1,j+n+1,1);
                    }
                }
            }
            for (int j=0 ; j<m ; ++j)
                addedge(j+n+1 , n+m+1 , c[j]);
            int match;
            match=sap(n+m+1);
            //printf("match = %d\n",match);
            if(n==match)
            {
                r=mid-1;
                ans=min(ans,mid);
            }
            else l=mid+1;
        }
        printf("%d\n",ans*cc*n);
    }
    return 0;
}


 

你可能感兴趣的:(匹配问题汇总)