匈牙利算法

匈牙利算法的本质是,不停地进行搜索找增广路,最后求出它的最大匹配.

以HDU2444为例,这道题先让判断是否是二分图,如果是求出它的最大匹配,那么就先用染色法,然后再用匈牙利算法

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
const int N=200+20;
int color[N],vis[N],match[N],n,m,pre;
vector<int>G[N];
int judge()//染色法判断二分图
{
    queue<int>q;
    q.push(pre);
    color[pre]=1;
    while(!q.empty())
    {
        int v1=q.front();
        q.pop();
        for(int i=0; i<G[v1].size(); i++)
        {
            int v2=G[v1][i];
            if(color[v2]==-1)
            {
                color[v2]=-color[v1];
                q.push(v2);
            }
            else if(color[v1]==color[v2])
                return 0;
        }
    }
    return 1;
}
int dfs(int u)
{
    for(int i=0; i<G[u].size(); i++)
    {
        int v=G[u][i];
        if(!vis[v])
        {
            vis[v]=1;
            if(match[v]==-1||dfs(match[v]))
            {
                match[v]=u;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int a,b;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=0; i<N; i++)G[i].clear();
        mem(color,-1);
        mem(match,-1);
        pre=0;
        while(m--)
        {
            scanf("%d%d",&a,&b);
            if(!pre)pre=a;
            G[a].push_back(b);
            G[b].push_back(a);
        }
        if(!judge())puts("No");
        else
        {
            int sum=0;
            for(int i=1; i<=n; i++)
            {
                mem(vis,0);
                if(dfs(i))sum++;
            }
            printf("%d\n",sum/2);
        }
    }
    return 0;
}

第二种模板:

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const int N=1000+20;
int e[N][N],vis[N],match[N],n;
int dfs(int u)
{
    for(int i=1; i<=num; i++)
    {
        if(e[u][i]&&!vis[i])
        {
            vis[i]=1;
            if(!match[i]||dfs(match[i]))
            {
                match[i]=u;
                return 1;
            }
        }
    }
    return 0;
}
int query()
{
    mem(match,0);
    int sum=0;
    for(int i=1; i<=num; i++)
    {
        mem(vis,0);
        if(dfs(i))sum++;
    }
    return sum;
}

HDU4185 Oil Skimming(二分图匹配,匈牙利算法)

有一个石油大亨要在一片N∗N区域里面打捞石油,它的网能网住的区域面积是1×2,#代表这个地方是石油,.代表这个地方是海水,问在这一片水域,最多能打捞多少石油(不能石油和海水一起捞)

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const int N=1000+20;
int e[N][N],vis[N],match[N],n,temp[N][N],num;
char s[N][N];
int dfs(int u)
{
    for(int i=1; i<=num; i++)
    {
        if(e[u][i]&&!vis[i])
        {
            vis[i]=1;
            if(!match[i]||dfs(match[i]))
            {
                match[i]=u;
                return 1;
            }
        }
    }
    return 0;
}
int query()
{
    mem(match,0);
    int sum=0;
    for(int i=1; i<=num; i++)
    {
        mem(vis,0);
        if(dfs(i))sum++;
    }
    return sum;
}
int main()
{
    int t,q=1;
    scanf("%d",&t);
    while(t--)
    {
        mem(temp,0);
        mem(e,0);
        num=0;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        {
            scanf("%s",s[i]+1);
            for(int j=1; j<=n; j++)
                if(s[i][j]=='#')
                    temp[i][j]=++num;
        }
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                if(s[i][j]=='#')
                {
                    if(i!=1&&s[i-1][j]=='#') e[temp[i][j]][temp[i-1][j]]=1;
                    if(j!=1&&s[i][j-1]=='#') e[temp[i][j]][temp[i][j-1]]=1;
                    if(i!=n&&s[i+1][j]=='#') e[temp[i][j]][temp[i+1][j]]=1;
                    if(j!=n&&s[i][j+1]=='#') e[temp[i][j]][temp[i][j+1]]=1;
                }
        printf("Case %d: %d\n",q++,query()/2);
    }
    return 0;
}

results matching ""

    No results matching ""