poj3189二分图多重匹配

题意:有一些牛和牛棚(有容量),每头牛对牛棚有喜好程度,要求每头牛都有一个棚子的情况下,找最小的喜好程度之差

题解:题意是真的恶心,wa了好久才发现没读懂,一直以为输入 的是排名,其实是牛棚标号,从1到m。用最大流一直tle,无奈还是用匈牙利算法,对于匈牙利算法求解二分图多重匹配,可以用一个容量数组来操作,如果容量没满,那么直接放进来,否则就遍历一遍,看是否有可能找到增广路,这题是二分差值,然后通过遍历找满足条件的最小结果。

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define C 0.5772156649
#define pi acos(-1.0)
#define ll long long
#define mod 20090717
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1

using namespace std;

const double g=10.0,eps=1e-12;
const int N=3000+10,maxn=20000+10,inf=0x3f3f3f3f;

int ra[N][30],c[30],num[30];
bool vis[30];
struct edge{
    int to,Next;
}e[maxn<<2];
int n,m,ans[30][N];
int cnt,head[N];
void add(int u,int v)
{
   // cout<<u<<" "<<v<<endl;
    e[cnt].to=v;
    e[cnt].Next=head[u];
    head[u]=cnt++;
}
bool match(int x)
{
    for(int i=head[x];~i;i=e[i].Next)
    {
        int y=e[i].to;
        if(vis[y])continue;
        vis[y]=1;
        if(num[y]<c[y])
        {
            ans[y][++num[y]]=x;
            return 1;
        }
        else
        {
            for(int j=1;j<=c[y];j++)
            {
                if(match(ans[y][j]))
                {
                    ans[y][j]=x;
                    return 1;
                }
            }
        }
    }
    return 0;
}
void init()
{
    cnt=0;
    for(int i=1;i<=n;i++)head[i]=-1;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            ans[i][j]=0;
    for(int i=1;i<=m;i++)num[i]=0;
}
bool isok(int x)
{
    for(int k=0; k+x<=m; k++)
    {
        init();
        for(int i=1; i<=n; i++)
            for(int j=k+1; j<=k+x; j++)
                add(i,ra[i][j]);
        int res=0;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)vis[j]=0;
            if(match(i))res++;
        }
        if(res==n)
        {
            return 1;
        }
    }
    return 0;
}
int main()
{
    /*ios::sync_with_stdio(false);
    cin.tie(0);*/
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1; i<=n; i++)
            for(int j=1; j<=m; j++)
                scanf("%d",&ra[i][j]);
        for(int i=1; i<=m; i++)scanf("%d",&c[i]);
        int l=0,r=m+1;
        while(r-l>1)
        {
            int mid=(l+r)/2;
            if(isok(mid))r=mid;
            else l=mid;
        }
        printf("%d\n",r);
    }
    return 0;
}
/********************
6 6
2 3 4 5 6 1
3 6 4 5 1 2
2 6 4 5 1 3
3 6 2 5 1 4
1 3 4 2 6 5
2 3 4 5 1 6
2 2 2 2 2 2
********************/
View Code

 

posted @ 2017-11-15 10:45  walfy  阅读(175)  评论(0编辑  收藏  举报