zoukankan      html  css  js  c++  java
  • HIT暑期集训 二分图匹配

    匈牙利求最大匹配数模板

    int dfs(int x)
    {
        for (int i=last[x];i;i=nxt[i])
        {
            if (!used[to[i]])
            {
                used[to[i]]=1;
                if (!match[to[i]] || dfs(match[to[i]]))
                {
                    match[to[i]]=x;
                    return 1;
                 }
             }
        }
        return 0;
    }
    匈牙利(部分)

    KM最大权匹配模板

    int dfs(int x)
    {
        int i,tmp;
        vis_g[x]=1;
        for (i=1;i<=n;i++)
        {
            if (vis_b[i]) continue;
            tmp=ex_g[x]+ex_b[i]-mp[x][i];
            if (tmp==0)
            {
                vis_b[i]=1;
                if (!match[i] || dfs(match[i]))
                {
                    match[i]=x;
                    return 1;
                }
            }
            else slack[i]=min(slack[i],tmp);
        }
        return 0;
    }
    int km()
    {
        int i,j,re=0,tmp;    
        for (i=1;i<=n;i++)
        {
            ex_g[i]=0;ex_b[i]=0;
            match[i]=0;
            for (j=1;j<=n;j++) ex_g[i]=max(ex_g[i],mp[i][j]);    
        }
        for (i=1;i<=n;i++)
        {
            for (j=1;j<=n;j++) slack[j]=inf;
            while (1)
            {
                memset(vis_g,0,sizeof(vis_g));
                memset(vis_b,0,sizeof(vis_b));
                if (dfs(i)) break;
                tmp=inf;
                for (j=1;j<=n;j++)
                    if (!vis_b[j]) tmp=min(tmp,slack[j]);
                for (j=1;j<=n;j++) 
                {
                    if (vis_g[j]) ex_g[j]-=tmp;
                    if (vis_b[j]) ex_b[j]+=tmp;
                    else slack[j]-=tmp;
                }
            }
        }
        for (i=1;i<=n;i++)
            re+=mp[match[i]][i];
        return re;
    }
    km最大权匹配

    C    HDU 1045

    建图+最大匹配。

    我们为每一行中被墙隔开的每一部分编上序号,为每一列中被墙隔开的每一部分也编上序号。对于每一个单位,当它被安上炮楼时意味着它对应的“行”和“列”(处理后的行和列)内不可放置炮楼,因此在每一个单位的“行”序号和“列”序号之间连边,求出的最大匹配就是能放置炮楼的最大数。(这题的代码几乎和E题一模一样)

    不过因为数据很小(n<=4),好像也可以直接搜索。。

    #include<cstdio>
    #include<cstring>
    #define maxn 20
    #define maxm 20
    using namespace std;
    int num,last[maxn],to[maxm],nxt[maxm],used[maxn],match[maxn],cnt;
    int a[maxn][maxn],b[maxn][maxn],cnta,cntb;
    char mp[maxn][maxn];
    int dfs(int x)
    {
        for (int i=last[x];i;i=nxt[i])
        {
            if (!used[to[i]])
            {
                used[to[i]]=1;
                if (!match[to[i]] || dfs(match[to[i]]))
                {
                    match[to[i]]=x;
                    return 1;
                 }
             }
        }
        return 0;
    }
    void add(int x,int y)
    {
        to[++num]=y;nxt[num]=last[x];last[x]=num;
    }
    int main()
    {
        int i,j,n,ans;
        while (scanf("%d",&n)!=EOF && n!=0)
        {
            for (i=1;i<=n;i++) scanf("%s",mp[i]+1);
            cnta=0;cntb=0;ans=0;num=0;
            memset(match,0,sizeof(match));
            memset(last,0,sizeof(last));
            for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)//竖向 
            {
                if (mp[i][j]=='X') continue;
                if (i!=1 && mp[i-1][j]=='.') a[i][j]=a[i-1][j];
                else a[i][j]=++cnta;
            }
            for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)//横向 
            {
                if (mp[i][j]=='X') continue;
                if (j!=1 && mp[i][j-1]=='.') b[i][j]=b[i][j-1];
                else b[i][j]=++cntb;
                add(a[i][j],b[i][j]);
            }
            for (i=1;i<=cnta;i++)
            {
                memset(used,0,sizeof(used));
                ans+=dfs(i);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    D    HDU 2448

    E    POJ 2226

    建图+最小顶点覆盖。

    对于每个一个单位的水洼,它既可以被横着的木板遮盖,也可以被竖着的木板遮盖。于是我们将每一条横着遮盖水洼的木板、每一条竖着遮盖水洼的木板分别编上号,对于每个一个单位的水洼在能够遮盖它的横木板和竖木板之间连边,可以发现这条边代表了这个水洼。由于对于每个水洼(边)要有一条木板(该边的两端点)遮盖,问题便转化为了求这个二分图的最小顶点覆盖。由于最小顶点覆盖等于最大匹配,于是这道题就可以当作二分图匹配做了。

    #include<cstdio>
    #include<cstring>
    #define maxn 2505
    #define maxm 2505
    using namespace std;
    int num,last[maxn],to[maxm],nxt[maxm],used[maxn],match[maxn],cnt;
    int a[maxn][maxn],b[maxn][maxn],cnta,cntb;
    char mp[maxn][maxn];
    int dfs(int x)
    {
        for (int i=last[x];i;i=nxt[i])
        {
            if (!used[to[i]])
            {
                used[to[i]]=1;
                if (!match[to[i]] || dfs(match[to[i]]))
                {
                    match[to[i]]=x;
                    return 1;
                 }
             }
        }
        return 0;
    }
    void add(int x,int y)
    {
        to[++num]=y;nxt[num]=last[x];last[x]=num;
    }
    int main()
    {
        int i,j,n,m,ans;
        while (scanf("%d%d",&n,&m)!=EOF)
        {
            for (i=1;i<=n;i++) scanf("%s",mp[i]+1);
            cnta=0;cntb=0;ans=0;num=0;
            memset(match,0,sizeof(match));
            memset(last,0,sizeof(last));
            for (i=1;i<=n;i++)
            for (j=1;j<=m;j++)//竖向 
            {
                if (mp[i][j]!='*') continue;
                if (i!=1 && mp[i-1][j]=='*') a[i][j]=a[i-1][j];
                else a[i][j]=++cnta;
            }
            for (i=1;i<=n;i++)
            for (j=1;j<=m;j++)//横向 
            {
                if (mp[i][j]!='*') continue;
                if (j!=1 && mp[i][j-1]=='*') b[i][j]=b[i][j-1];
                else b[i][j]=++cntb;
                add(a[i][j],b[i][j]);
            }
            for (i=1;i<=cnta;i++)
            {
                memset(used,0,sizeof(used));
                ans+=dfs(i);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    F    HDU 3718

    H    POJ 2060

    I    HDU 2819

    J    HDU 2853

  • 相关阅读:
    自定义类型百度地图之自定义地图类型详解
    电话文本android(3)_拨打电话操作
    检查运行IIS 5.1 使用出现server application error解决方法
    function运行令人吐血的IE JS兼容性问题。。。
    组件设置window2008 64位系统无法调用Microsoft.Office.Interop组件进行文件另存的解决办法
    api时间转换VarDateFromStr,VariantTimeToSystemTime
    C与CPP文件的区别
    OpenSSL 使用指南
    Pascal保留字/关键字列表
    windbg 启动参数,常用命令
  • 原文地址:https://www.cnblogs.com/lsykk/p/13505575.html
Copyright © 2011-2022 走看看