zoukankan      html  css  js  c++  java
  • HDU

    1、男生女生一起坐过山车,每一排有两个座位,但是有个条件,就是每个女生必须找个男生做同伴一起(但是女生只愿意和某几个男生中的一个做同伴),求最多可以有多少对男女生组合坐上过山车。

    2、二分图的最大匹配,女生作为X集合(左边),男生作为Y集合(右边)

    3、

    3.1匈牙利算法(邻接矩阵):

    /*
    顶点编号从0开始的
    邻接矩阵(匈牙利算法)
    二分图匹配(匈牙利算法的DFS实现)(邻接矩阵形式)
    初始化:g[][]两边顶点的划分情况
    建立g[i][j]表示i->j的有向边就可以了,是左边向右边的匹配
    g没有边相连则初始化为0
    uN是匹配左边的顶点数,vN是匹配右边的顶点数
    左边是X集,右边是Y集
    调用:res=hungary();输出最大匹配数
    优点:适用于稠密图,DFS找增广路,实现简洁易于理解
    时间复杂度:O(VE)
    */
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    
    const int MAXN=512;
    int uN,vN;//u,v 的数目,使用前面必须赋值
    int g[MAXN][MAXN];//邻接矩阵,记得初始化
    int linker[MAXN];//linker[v]=u,表示v(右边Y集合中的点)连接到u(左边X集合中的点)
    bool used[MAXN];
    bool dfs(int u){//判断以X集合中的节点u为起点的增广路径是否存在
        for(int v=0;v<vN;v++)//枚举右边Y集合中的点
            if(g[u][v]&&!used[v]){//搜索Y集合中所有与u相连的未访问点v
                used[v]=true;//访问节点v
                if(linker[v]==-1||dfs(linker[v])){//是否存在增广路径
                    //若v是未盖点(linker[v]==-1表示没有与v相连的点,即v是未盖点),找到增广路径
                    //或者存在从与v相连的匹配点linker[v]出发的增广路径
                    linker[v]=u;//设定(u,v)为匹配边,v连接到u
                    return true;//返回找到增广路径
                }
            }
            return false;
    }
    int hungary(){//返回最大匹配数(即最多的匹配边的条数)
        int res=0;//最大匹配数
        memset(linker,-1,sizeof(linker));//匹配边集初始化为空
        for(int u=0;u<uN;u++){//找X集合中的点的增广路
            memset(used,false,sizeof(used));//设Y集合中的所有节点的未访问标志
            if(dfs(u))res++;//找到增广路,匹配数(即匹配边的条数)+1
        }
        return res;
    }
    
    int main(){
        int i,ans;
        int K,M,N;//K边数,M是左边的顶点数,N是右边的顶点数
        int u,v;
        while(~scanf("%d",&K)){
            if(K==0)break;
            scanf("%d%d",&M,&N);
            uN=M;//匹配左边的顶点数
            vN=N;//匹配右边的顶点数
            memset(g,0,sizeof(g));//二分图的邻接矩阵初始化
            for(i=0;i<K;++i){
                scanf("%d%d",&u,&v);
                g[--u][--v]=1;//顶点编号从0开始的
            }
            ans=hungary();
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    3.2匈牙利算法(邻接表):

    /*
    //顶点编号从0开始的
    匈牙利算法邻接表形式
    使用前用init()进行初始化,给uN赋值
    加边使用函数addedge(u,v)
    */
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    
    const int MAXN=512;//点数的最大值
    const int MAXM=1024;//边数的最大值
    struct Edge{
        int to,next;
    }edge[MAXM];
    int head[MAXN],tot;
    void init(){
        tot=0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int u,int v){
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    int linker[MAXN];
    bool used[MAXN];
    int uN;
    bool dfs(int u){
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(!used[v]){
                used[v]=true;
                if(linker[v]==-1||dfs(linker[v])){
                    linker[v]=u;
                    return true;
                }
            }
        }
        return false;
    }
    int hungary(){
        int res=0;
        memset(linker,-1,sizeof(linker));
        //点的编号0~uN-1
        for(int u=0;u<uN;u++){
            memset(used,false,sizeof(used));
            if(dfs(u))res++;
        }
        return res;
    }
    int main(){
        int i,ans;
        int K,M,N;
        int u,v;
        while(~scanf("%d",&K)){
            if(K==0)break;
            scanf("%d%d",&M,&N);
            uN=M;//匹配左边的顶点数
            init();//初始化
            for(i=0;i<K;++i){
                scanf("%d%d",&u,&v);
                addedge(--u,--v);//顶点编号从0开始的
            }
            ans=hungary();
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    3.3匈牙利算法(邻接表,用vector实现):

    /*
    //顶点编号从1开始的
    用STL中的vector建立邻接表实现匈牙利算法
    效率比较高
    处理点比较多的效率很高。1500的点都没有问题
    */
    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #include<string.h>
    #include<vector>
    using namespace std;
    
    const int MAXN=512;//这个值要超过两边个数的较大者,因为有linker
    int linker[MAXN];
    bool used[MAXN];
    vector<int>G[MAXN];
    int uN;
    bool dfs(int u)
    {
        int sz=G[u].size();
        for(int i=0; i<sz; i++)
        {
            if(!used[G[u][i]])
            {
                used[G[u][i]]=true;
                if(linker[G[u][i]]==-1||dfs(linker[G[u][i]]))
                {
                    linker[G[u][i]]=u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int hungary()
    {
        int u;
        int res=0;
        memset(linker,-1,sizeof(linker));
        for(u=1; u<=uN; u++)
        {
            memset(used,false,sizeof(used));
            if(dfs(u)) res++;
        }
        return res;
    }
    
    int main()
    {
        int i,ans;
        int K,M,N;
        int u,v;
        while(~scanf("%d",&K))
        {
            if(K==0)break;
            scanf("%d%d",&M,&N);
            uN=M;//匹配左边的顶点数
            for(i=0; i<MAXN; i++)//二分图的邻接表初始化
                G[i].clear();
            for(i=0; i<K; ++i)
            {
                scanf("%d%d",&u,&v);
                G[u].push_back(v);//顶点编号从1开始的
            }
            ans=hungary();
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    3.4Hopcroft-Karp算法(邻接矩阵):

    /* *********************************************
    //顶点编号从1开始的
    二分图匹配(Hopcroft-Carp的算法)。
    初始化:g[][]邻接矩阵
    调用:res=MaxMatch();  Nx,Ny要初始化!!!
    时间复杂大为 O(V^0.5 E)
    适用于数据较大的二分匹配
    需要queue头文件
    ********************************************** */
    #include<iostream>
    #include<stdio.h>
    #include<queue>
    #include<string.h>
    using namespace std;
    const int MAXN=512;
    const int INF=1<<28;
    int g[MAXN][MAXN],Mx[MAXN],My[MAXN],Nx,Ny;
    int dx[MAXN],dy[MAXN],dis;
    bool vst[MAXN];
    bool searchP()
    {
        queue<int>Q;
        dis=INF;
        memset(dx,-1,sizeof(dx));
        memset(dy,-1,sizeof(dy));
        for(int i=1; i<=Nx; i++)
            if(Mx[i]==-1)
            {
                Q.push(i);
                dx[i]=0;
            }
        while(!Q.empty())
        {
            int u=Q.front();
            Q.pop();
            if(dx[u]>dis)  break;
            for(int v=1; v<=Ny; v++)
                if(g[u][v]&&dy[v]==-1)
                {
                    dy[v]=dx[u]+1;
                    if(My[v]==-1)  dis=dy[v];
                    else
                    {
                        dx[My[v]]=dy[v]+1;
                        Q.push(My[v]);
                    }
                }
        }
        return dis!=INF;
    }
    bool DFS(int u)
    {
        for(int v=1; v<=Ny; v++)
            if(!vst[v]&&g[u][v]&&dy[v]==dx[u]+1)
            {
                vst[v]=1;
                if(My[v]!=-1&&dy[v]==dis) continue;
                if(My[v]==-1||DFS(My[v]))
                {
                    My[v]=u;
                    Mx[u]=v;
                    return 1;
                }
            }
        return 0;
    }
    int MaxMatch()
    {
        int res=0;
        memset(Mx,-1,sizeof(Mx));
        memset(My,-1,sizeof(My));
        while(searchP())
        {
            memset(vst,0,sizeof(vst));
            for(int i=1; i<=Nx; i++)
                if(Mx[i]==-1&&DFS(i))  res++;
        }
        return res;
    }
    
    int main()
    {
        int i,ans;
        int K,M,N;
        int u,v;
        while(~scanf("%d",&K))
        {
            if(K==0)break;
            scanf("%d%d",&M,&N);
            Nx=M;//匹配左边的顶点数
            Ny=N;//匹配右边的顶点数
            memset(g,0,sizeof(g));//二分图的邻接矩阵初始化
            for(i=0; i<K; ++i)
            {
                scanf("%d%d",&u,&v);
                g[u][v]=1;//顶点编号从1开始的
            }
            ans=MaxMatch();
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    3.5Hopcroft-Karp算法(邻接表,用vector实现):

    /*
    //顶点编号从0开始的
    二分图匹配(Hopcroft-Karp算法)
    复杂度O(squt(n)*E)
    邻接表存图,vector实现
    vector先初始化,然后加入边
    uN为左端的顶点数,使用前赋值(点编号0开始)
    */
    #include<iostream>
    #include<stdio.h>
    #include<vector>
    #include<queue>
    #include<string.h>
    using namespace std;
    
    const int MAXN=512;
    const int INF=0x3f3f3f3f;
    vector<int>G[MAXN];
    int uN;
    int Mx[MAXN],My[MAXN];
    int dx[MAXN],dy[MAXN];
    int dis;
    bool used[MAXN];
    bool SearchP(){
        queue<int>Q;
        dis=INF;
        memset(dx,-1,sizeof(dx));
        memset(dy,-1,sizeof(dy));
        for(int i=0;i<uN;i++)
            if(Mx[i]==-1){
                Q.push(i);
                dx[i]=0;
            }
        while(!Q.empty()){
            int u=Q.front();
            Q.pop();
            if(dx[u]>dis)break;
            int sz=G[u].size();
            for(int i=0;i<sz;i++){
                int v=G[u][i];
                if(dy[v]==-1){
                    dy[v]=dx[u]+1;
                    if(My[v]==-1)dis=dy[v];
                    else{
                        dx[My[v]]=dy[v]+1;
                        Q.push(My[v]);
                    }
                }
            }
        }
        return dis!=INF;
    }
    bool DFS(int u){
        int sz=G[u].size();
        for(int i=0;i<sz;i++){
            int v=G[u][i];
            if(!used[v]&&dy[v]==dx[u]+1){
                used[v]=true;
                if(My[v]!=-1&&dy[v]==dis)continue;
                if(My[v]==-1||DFS(My[v])){
                    My[v]=u;
                    Mx[u]=v;
                    return true;
                }
            }
        }
        return false;
    }
    int MaxMatch(){
        int res=0;
        memset(Mx,-1,sizeof(Mx));
        memset(My,-1,sizeof(My));
        while(SearchP()){
            memset(used,false,sizeof(used));
            for(int i=0;i<uN;i++)
                if(Mx[i]==-1&&DFS(i))
                    res++;
        }
        return res;
    }
    
    int main(){
        int i,ans;
        int K,M,N;
        int u,v;
        while(~scanf("%d",&K)){
            if(K==0)break;
            scanf("%d%d",&M,&N);
            uN=M;//匹配左边的顶点数
            for(i=0;i<MAXN;++i)//二分图的邻接表初始化
                G[i].clear();
            for(i=0;i<K;++i){
                scanf("%d%d",&u,&v);
                G[--u].push_back(--v);//顶点编号从0开始的
            }
            ans=MaxMatch();
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    ASP.NET Core2利用MassTransit集成RabbitMQ
    ASP.NET Core2集成Office Online Server(OWAS)实现办公文档的在线预览与编辑(支持wordexcelpptpdf等格式)
    ASP.NET Core2利用Jwt技术在服务端实现对客户端的身份认证
    net core System.Drawing is not supported on this platform.
    小程序开发之维护access_token
    net core 100个案例
    msgSystem.Drawing is not supported on this platform【netcore】
    wpf,前端动画demo,鱼眼效果
    自定义控件,重写 TextBox 实例
    TextBox输入法控制,进入输入框则启用或禁用输入法(ime),禁用后只能输入英文
  • 原文地址:https://www.cnblogs.com/gongpixin/p/4977457.html
Copyright © 2011-2022 走看看