HLG 1392 (POJ 2112 Optimal Milking)【二分+二分图多重匹配 + 最大流】

题意: 给你 n 个机器,m 头牛,每台机器最多可供 cap 头牛使用,并告诉你每个物体之间的距离,找出一个距离满足所有的牛都分配到机器且里面走最远的牛

    走的距离最小。

分析: 用 floyd 计算出每个物体的最短距离,然后二分枚举距离,如果在该距离下满足完全匹配,该距离即为合法距离,匹配用到多重匹配。

 二分图多重匹配
#include<stdio.h>
#include<string.h>
#define clr(x)memset(x,0,sizeof(x))
int cap;
int link[33][202];
int vlink[33];
int v[33];
struct node
{
    int to,next;
}q[200000];
int head[202];
int g[240][240];
int tot;
int n,m;
void add(int s,int u)
{
    q[tot].to=u;
    q[tot].next=head[s];
    head[s]=tot++;
}
int find(int x)
{
    int i,j,k;
    for(i=head[x];i;i=q[i].next)
    {
        k=q[i].to;
        if(!v[k])
        {
            v[k]=1;
            if(vlink[k]<cap)
            {
                link[k][vlink[k]++]=x;
                return 1;
            }
            for(j=0;j<vlink[k];j++)
            {
                if(find(link[k][j]))
                {
                    link[k][j]=x;
                    return 1;
                }
            }
        }
    }
    return 0;
}
int ok(int ti)
{
    int i,j,sum=0;
    tot=1;
    clr(head);
    clr(vlink);
    for(i=n+1;i<=n+m;i++)
        for(j=1;j<=n;j++)
            if(g[i][j]&&g[i][j]<=ti)
                add(i-n,j);
    for(i=1;i<=m;i++)
    {
        clr(v);
        if(find(i))
            sum++;
        else break;
    }
    if(sum==m)
        return 1;
    return 0;
}
int main()
{
    int i,j,k,low,high,mid;
    while(scanf("%d%d%d",&n,&m,&cap)!=EOF)
    {
        for(i=1;i<=n+m;i++)
            for(j=1;j<=n+m;j++)
                scanf("%d",&g[i][j]);
        for(k=1;k<=n+m;k++)
            for(i=1;i<=n+m;i++)
            {
                if(g[i][k])
                for(j=1;j<=n+m;j++)
                    if(g[k][j]&&(g[i][k]+g[k][j]<g[i][j]||g[i][j]==0))
                        g[i][j]=g[i][k]+g[k][j];
            }
        low=0;
        high=0;
        for(i=n+1;i<=n+m;i++)
            for(j=1;j<=n;j++)
                if(g[i][j]>high)
                    high=g[i][j];
        while(low<high)
        {
            mid=(low+high)>>1;
            if(ok(mid))
                high=mid;
            else low=mid+1;
        }
        printf("%d\n",low);
    }
    return 0;
}

 最大流做法:

#include<stdio.h>
#include<string.h>
#define INF 0x1f;
int n,m,s,u,e;
int cap;
int c[232][232];
int gap[232];
int dis[232];
int g[232][232];
void init()
{
    int v,x,q[232],front=0,rear=0;
    memset(gap,0,sizeof(gap));
    memset(dis,0xff,sizeof(dis));
    q[rear++]=u;
    dis[u]=0;
    while(front<rear)
    {
        x=q[front++];
        gap[dis[x]]++;
        for(v=0;v<=e;v++)
            if(dis[v]==-1&&c[v][x]>0)
            {
                dis[v]=dis[x]+1;
                q[rear++]=v;
            }
    }
}
int sap()
{
    init();
    int flow=0,top=s,i,j,k,pre[232],low[232];
    //memset(low,0,sizeof(low));
    while(dis[s]<=e)
    {
        int flag=0;
        low[s]=INF;
        for(i=0;i<=e;i++)
            if(c[top][i]>0&&dis[top]==dis[i]+1&&dis[i]>=0)
            {
                flag=1;
                break;
            }
        if(flag)
        {
            low[i]=c[top][i];
            if(low[i]>low[top])
                low[i]=low[top];
            pre[i]=top;
            top=i;
            if(top==u)
            {
                flow+=low[u];
                j=top;
                while(j!=s)
                {
                    k=pre[j];
                    c[k][j]-=low[u];
                    c[j][k]+=low[u];
                    j=k;
                }
                top=s;
                memset(low,0,sizeof(low));
            }
        }
        else 
        {
            int min=e;
            for(j=0;j<=e;j++)
                if(c[top][j]>0&&dis[j]+1<min&&dis[j]>=0)
                    min=dis[j]+1;
            gap[dis[top]]--;
            if(gap[dis[top]]==0)
                break;
            gap[min]++;
            dis[top]=min;
            if(top!=s)
                top=pre[top];
        }
    }
    return flow;
}
int ok(int ti)
{
    int i,j,sum;
    memset(c,0,sizeof(c));
    s=0;                           // 超级源点 s   0
    e=u=n+m+1;                     // 超级汇点 u   n+m+1
    for(i=n+1;i<=n+m;i++)          // 牛的编号为   n+1..n+m
        c[0][i]=1;                 // 机器的编号为 1..n
    for(i=n+1;i<=n+m;i++)              
        for(j=1;j<=n;j++)
            if(g[i][j]&&g[i][j]<=ti) // 如果牛和机器之间有边,且边距离小于 ti,
                c[i][j]=1;           // 容量设为 1
    for(i=1;i<=n;i++) 
        c[i][u]=cap;                 // 机器和汇点之间连边
    sum=sap();                       // 求最大流
    if(sum==m)                        // 最大流为 牛的数量
        return 1;
    return 0;
}
int main()
{
    int i,j,k,low,high,mid,t;
    while(scanf("%d%d%d",&n,&m,&cap)!=EOF)
    {
        for(i=1;i<=n+m;i++)
            for(j=1;j<=n+m;j++)
                scanf("%d",&g[i][j]);
        for(k=1;k<=n+m;k++)
            for(i=1;i<=n+m;i++)
            {
                if(g[i][k])
                for(j=1;j<=n+m;j++)
                    if(g[k][j]&&(g[i][k]+g[k][j]<g[i][j]||g[i][j]==0))
                        g[i][j]=g[i][k]+g[k][j];
            }
        low=0;
        high=0;
        for(i=n+1;i<=n+m;i++)
            for(j=1;j<=n;j++)
                if(g[i][j]>high)
                    high=g[i][j];
        while(low<high)        //  二分枚举答案
        {
            mid=(low+high)>>1;
            if(ok(mid))       //   枚举的答案可以保证 每头牛都分配到机器
                high=mid;
            else low=mid+1;
        }

        printf("%d\n",low);
    }
    return 0;
}

 

 

转载于:https://www.cnblogs.com/dream-wind/archive/2012/04/22/2464883.html

引用:OpenCvSharp是一个OpenCV的.Net wrapper,用于开发基于OpenCV的应用程序,它与原始的OpenCV更接近,并提供了详细的使用样例。 引用:对于使用OpenCV进行图像处理的代码示例,可以使用import numpy as np import cv2来导入OpenCV库,并使用cv2.imread、cv2.imshow等函数进行图像的读取和显示。 引用:如果想要使用OpenCV进行分类器的生成,可以使用opencv_traincascade.exe命令,并提供指定的参数,例如-data用于指定生成的分类器的保存路径,-vec用于指定正样本描述文件的路径,-bg用于指定负样本文件的路径,以及其他参数如numPos、numNeg、minHitRate等。 关于"opencv hlg"的问题,根据提供的引用内容,我没有找到与"opencv hlg"相关的具体信息。可能需要提供更多背景或上下文信息来解答该问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [OpenCvSharp](https://download.csdn.net/download/qq_18865111/86722032)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [python opencv 读取图片 存储图片](https://blog.csdn.net/weixin_41799483/article/details/80829825)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [opencv分类器训练方法](https://blog.csdn.net/weixin_41799483/article/details/80567909)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值