1. 程式人生 > >二分圖——匈牙利演算法

二分圖——匈牙利演算法

匈牙利演算法參考連結:

https://blog.csdn.net/sixdaycoder/article/details/47680831

https://www.renfei.org/blog/bipartite-matching.html

 

題目一:

hdu 1083

題意:

一共有N個學生跟P門課程,一個學生可以任意選一 門或多門課,問是否達成:

 1.每個學生選的都是不同的課(即不能有兩個學生選同一門課)

 2.每門課都有一個代表(即P門課都被成功選過)

輸入為:

第一行一個T代表T組資料

P N(P課程數, N學生數)

接著P行:

第幾行代表第幾門課程,首先是一個數字k代表對這門課程感興趣的同學的個數,接下來是k個對這門課程感興趣同學的編號。

 

題解:直接建個二分圖搞定。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>

using namespace std;

const int maxn=310;

vector<int> G[maxn];

int match[maxn];
bool check[maxn];

bool dfs(int u)
{
    for(int i=0;i<G[u].size();i++)
    {

        int v=G[u][i];

        if(!check[v]){
            check[v]=true;

            if(match[v]==-1||dfs(match[v])){
                match[v]=u; ///學生匹配課程
                return true;
            }
        }
    }

    return false;
}

int hungarian(int num_left)
{
    int ans=0;
    memset(match,-1,sizeof(match));

    for(int u=0;u<num_left;u++)
    {
            memset(check,0,sizeof(check));

            if(dfs(u)) ans++;
    }

    return ans;
}



int main()
{
    int ncase;

    scanf("%d",&ncase);

    while(ncase--)
    {
        int p,n;
        scanf("%d%d",&p,&n);

        for(int i=0;i<p;i++) ///課程
        {
            G[i].clear();
            int counts,x;
            scanf("%d",&counts);

            while(counts--)
            {
                scanf("%d",&x);
                G[i].push_back(x);  ///課程i被學生x所喜歡
            }
        }

       int ans=hungarian(p);
//       printf("ans=%d\n",ans);

       if(p-ans==0) puts("YES");
       else puts("NO");


    }

    return 0;

}

 

題目二:

zoj 1654

參考連結:https://blog.csdn.net/wchhlbt/article/details/76687002

https://www.2cto.com/kf/201308/233630.html

題意:見連結。

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

const int maxn=51;
char op[maxn][maxn];

int x[maxn][maxn],y[maxn][maxn];

int maps[maxn*maxn][maxn*maxn];

bool vis[maxn*maxn];
int cx[maxn*maxn],cy[maxn*maxn];

int xpiece,ypiece;

int dfs(int u)
{
    for(int v=1;v<=ypiece;v++)
    {
        if(maps[u][v]&&!vis[v]){
            vis[v]=1;

            if(cy[v]==-1||dfs(cy[v]))
            {
                cy[v]=u;
                return 1;
            }
        }
    }
    return 0;
}

int hungarian()
{
    memset(cy,-1,sizeof(cy));

   int res=0;

    for(int i=1;i<=xpiece;i++)
    {
        memset(vis,0,sizeof(vis));
        res+=dfs(i);
    }
    return res;
}

int main()
{
    int ncase;

    scanf("%d",&ncase);
    int T=0;

    while(ncase--)
    {
        int m,n;
        scanf("%d%d",&m,&n);


        for(int i=0;i<m;i++)
            scanf("%s",op[i]);

        bool flag;

        memset(x,0,sizeof(x)); ///初始化
        memset(y,0,sizeof(y));
        memset(maps,0,sizeof(maps));

        xpiece=ypiece=0;
        for(int i=0;i<m;i++) ///對橫向分塊
        {
            flag=true;

            for(int j=0;j<n;j++){
                if(op[i][j]=='o'){

                    if(flag)
                        x[i][j]=++xpiece,flag=false;
                    else x[i][j]=xpiece;
                }
                else if(op[i][j]=='#') flag=true;

            }
        }

        for(int j=0;j<n;j++) ///對縱向分塊
        {
            flag=true;
            for(int i=0;i<m;i++){
                if(op[i][j]=='o'){
                    if(flag) y[i][j]=++ypiece,flag=false;
                    else y[i][j]=ypiece;
                }
                else if(op[i][j]=='#') flag=true;
            }
        }


        for(int i=0;i<m;i++) ///建圖
        {
            for(int j=0;j<n;j++)
            {
                if(x[i][j]) {
                maps[x[i][j]][y[i][j]]=1;
                }
            }
        }

      int sum=hungarian();

       printf("Case :%d\n%d\n",++T,sum);
    }

}