POJ_2112:Optimal Milking——(二分图多重匹配)

题目传送门
题目大意:
先给你三个数,n,m,k,分别表示挤奶机的个数n,奶牛的个数m,还有每个挤奶机最多能挤k个奶牛。
然后给你了一个e(n+m)*(n+m)的矩阵,1~n表示挤奶机,n+1到m表示奶牛,e[i][j]表示i到j之间的距离。然后让你求的是所有的奶牛都挤奶,所有奶牛走的距离的最大值尽可能的小,然后输出这个最小值。
思路
先用floyd来把整张图跑一遍,求出任意两点的最小距离。然后构建二分图,机器和奶牛之间为两个集合,然后让你求最大值的最小值,肯定是用二分答案ans,判断是否符合,在构建奶牛和机器二分图的时候,如果当前枚举的最小距离为limit,那么奶牛和机器之间的距离大于limit的话就是不能匹配,小于limit就说是可以匹配,然后匈牙利跑就可以了。
wa了好久,最后怎么也没想到是floyd出锅了(傻掉了都)

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
int e[500][500];
int n,m,l;
struct zxc
{
    int num;
    int k[500];
}line[500];
int oo=1e8;
int vis[500];
void floyd()
{for(int k=1;k<=n+m;k++)//我一直以为这个在下面和上面没有区别,就没有管他。。。。。
    for(int i=1;i<=n+m;i++)
    {
        for(int j=1;j<=n+m;j++)
        {
//            if(e[i][j]==oo)
//            {
//                continue;
//            }
            
            {
                if(e[i][j]>e[i][k]+e[k][j])
                {
                    e[i][j]=e[i][k]+e[k][j];

                }
            }
//            printf("%d ",e[i][j]);

        }
//        printf("\n");
    }
}
int erft(int u,int limit)
{
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]&&e[u][i]<=limit)//小于枚举的限制就说明可以链接。
        {
            vis[i]=1;
            if(line[i].num<l)//小于匹配数量,还可以匹配。
            {
                line[i].k[line[i].num++]=u;
                return 1;
            }
            for(int j=0;j<l;j++)//达到匹配数量,看看有没有可以腾开的。
            {
                if(erft(line[i].k[j],limit))
                {
                    line[i].k[j]=u;
                    return 1;
                }
            }
        }
    }
    return 0;
}
int fin(int limit)
{
    memset(line,0,sizeof(line));
    for(int i=1+n;i<=n+m;i++)
    {
        memset(vis,0,sizeof(vis));
        if(!erft(i,limit))//有一个奶牛不能被挤奶,那么当前的枚举的就不符合要求。
        {
            return 0;
        }
    }
    return 1;
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&l))
    {
        memset(e,0,sizeof(e));
        int w=n+m;
        for(int i=1;i<=w;i++)
        {
            for(int j=1;j<=w;j++)
            {
                scanf("%d",&e[i][j]);
                if(e[i][j]==0)
                {
                    e[i][j]=oo;
                }
            }
        }
        floyd();
        int l=1,r=1e8;
        int ans=10000000;
        while(l<=r)//二分答案
        {
            int mid=(l+r)/2;
            if(fin(mid))
            {
                r=mid-1;
                ans=mid;
            }
            else
            {
                l=mid+1;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
发布了42 篇原创文章 · 获赞 5 · 访问量 933

猜你喜欢

转载自blog.csdn.net/qq_43402296/article/details/103830351