二分图最优多重匹配(poj 2112)

      题目意思是找出奶牛到挤奶机的所有最短距离中的最大值,且挤奶机的容量有限制。这里的做法是寻找二分图的最优多重匹配,要求匹配的权值最小,用floyd+二分枚举最短距离的最大值+最大流验证存在性来做。至于二分图的最优多重匹配的相关知识可以看我的上一个blog,里面有个链接。

 

      以下是代码:

 

  1. #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=300;
    const int inf=1<<29;
    int min(int a,int b) {return a<b?a:b;}
    int s,t;
    int map[N][N],flow[N][N],pre[N];
    int k,c,m,n;
  2. void init()
    {
     memset(flow,0,sizeof(flow));
    }
  3. void floyd()
    {
     int i,j,k;
     for(k=1;k<=n;k++)
      for(i=1;i<=n;i++)
       for(j=1;j<=n;j++)
       {
        if(i!=j && map[i][k]!=inf && map[k][j]!=inf)
        {
         if(map[i][j]>map[i][k]+map[k][j])
          map[i][j]=map[i][k]+map[k][j];
        }
       }
    }
  4. bool bfs()
    {
     int i,now;
     queue<int> q;
     memset(pre,-1,sizeof(pre));
     q.push(s);
     while(!q.empty())
     {
      now=q.front();
      q.pop();
      for(i=0;i<=t;i++)
      {
       if(pre[i]==-1 && flow[now][i]>0)
       {
        pre[i]=now;
        if(i==t) return true;
        q.push(i);
       }
      }
     }
     return false;
    }
  5. int MaxFlow()
    {
     int i,j,sum=0;
     while(bfs())
     {
      int min=inf;
      for(i=t;i!=s;i=pre[i])
      {
       if(flow[pre[i]][i]<min)
        min=flow[pre[i]][i];
      }
      for(i=t;i!=s;i=pre[i])
      {
       flow[pre[i]][i]-=min;
       flow[i][pre[i]]+=min;
      }
      sum+=min;
     }
     return sum;
    }
  6. bool check(int mid)
    {
     init();
     int i,j;
     for(i=1;i<=k;i++)
      for(j=k+1;j<=n;j++)
       if(mid>=map[i][j])
        flow[i][j]=1;
     for(i=1;i<=k;i++)
      flow[s][i]=m;
     for(i=k+1;i<=n;i++)
      flow[i][t]=1;
     return MaxFlow()==c;
    }
  7. int main()
    {
  8.  scanf("%d%d%d",&k,&c,&m);
     int i,j;
     n=k+c;
     s=0;t=n+1;
     for(i=1;i<=n;i++)
      for(j=1;j<=n;j++)
      {
       scanf("%d",&map[i][j]);
       if(map[i][j]==0 && i!=j)
        map[i][j]=inf;
      }
     floyd();
     int max=0;
     for(i=1;i<=n;i++)
      for(j=1;j<=n;j++)
      {
       if(map[i][j]>max)
        max=map[i][j];
      }
     int low=0,high=max,ans=0;
     while(low<=high)
     {
      int mid=(low+high)/2;
      if(check(mid))
      {
       ans=mid;
       high=mid-1;
      }
      else low=mid+1;
     }
     printf("%d/n",ans);
     return 0;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值