第七周周赛之二分匹配

最大匹配,最小点覆盖,最大点独立,最小边覆盖,最大边独立,最小路径覆盖

最大匹配:匈牙利算法

最小点覆盖=最大匹配

最大点独立=n(顶点数)-最小点覆盖

最大边独立=n-最小边覆盖

最小路径覆盖=p(n/2)-最大匹配  (p*p的有向图)

1001:

hdu1150:http://acm.hdu.edu.cn/showproblem.php?pid=1150

最大匹配等于最小点覆盖:匈牙利算法模版

代码:

#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int nMax = 105;
int n, m, k;
int map[nMax][nMax];
int link[nMax];
int useif[nMax];

bool can(int t)
{
    for(int i = 1; i <= m; ++ i)
    {
        if(!useif[i] && map[t][i])
        {
            useif[i] = 1;
            if(link[i] == -1 || can(link[i]))
            {
                link[i] = t;
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
    while(1)
    {
        memset(map, 0, sizeof(map));
        memset(link, -1, sizeof(link));
        int num = 0;
        scanf("%d", &n);
        if(!n) break;
        scanf("%d%d", &m, &k);
        for(int i = 0; i < k; ++ i)
        {
            int a, b, c;
            scanf("%d %d %d", &a, &b, &c);
            map[b][c] = 1;
        }
        for(int i = 1; i <= n; ++ i)
        {
            memset(useif, 0, sizeof(useif));
            if(can(i)) ++ num;
        }
        printf("%d\n", num);
    }
    return 0;
}
1002:

hdu1498:http://acm.hdu.edu.cn/showproblem.php?pid=1498

不太好想,行和列为两个点集合,边为一个气球的坐标,判断某个颜色的气球的最大点覆盖,恰好使用每次都使用一行和一列。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 111
using namespace std;
int n,k;
int vis[maxn],link[maxn],map[maxn][maxn];
int min(int x,int y)
{
    return x>y?y:x;
}
int getnum(int x,int c)
{
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]&&map[x][i]==c)
        {
            vis[i]=1;
            if(!link[i]||getnum(link[i],c))
            {
                link[i]=x;
                return 1;
            }
        }
    }
    return 0;
}
int dfs(int c)
{
    int count=0;
    memset(link,0,sizeof(link));
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));
        if(getnum(i,c))
        count++;
    }
    return count;
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        if(n==0&&k==0) break;

        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&map[i][j]);
        }
        int t=0;
        for(int i=1;i<=50;i++)
        {
            if(dfs(i)>k&&t==0)
            {
                printf("%d",i);
                t=1;
            }
            else if(dfs(i)>k&&t==1)
            {
                printf(" %d",i);
            }
        }

        if(t==0)
        {
            printf("-1\n");
        }
        else
        printf("\n");
    }
    return 0;
}

1003:

hdu1068:http://acm.hdu.edu.cn/showproblem.php?pid=1068

最大点独立集=n-最小点覆盖

点用了两次,要除以2;也可以认为为双向边。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<queue>
#define INF 0x7fffffff
#define maxn 1000
#define maxl 0x7fffffff
#define fi for(int i=0;i<n;i++)
#define fj for(int j=0;j<n;j++)
#define wh while(t--)
using namespace std;
int map[maxn][maxn];
int vis[maxn],link[maxn];
int n,m;
void init()
{
    memset(link,-1,sizeof(link));
    memset(map,0,sizeof(map));
}
bool getnum(int x)
{
    for(int i=0; i<n; i++)
    {
        if(!vis[i]&&map[x][i])
        {
            vis[i]=1;
            if(link[i]==-1||getnum(link[i]))
            {
                link[i]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int b,t;

    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=0; i<n; i++)
        {
            scanf("%d: (%d)",&t,&m);
            for(int j=0; j<m; j++)
            {
                scanf("%d",&b);
                map[i][b]=1;
                map[b][i]=1;
            }
        }
        int count=0;
        for(int i=0; i<n; i++)
        {
            memset(vis,0,sizeof(vis));
            if(getnum(i))
                count++;
        }
        printf("%d\n",n-count/2);
    }
    return 0;
}

1004:

hdu3289:http://acm.hdu.edu.cn/showproblem.php?pid=3829

以每个小孩为点,冲突的小孩的点相连,求最大点独立集。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define maxn 555
using namespace std;
int n,m,p,aln,count;
int vis[maxn],link[maxn],map[maxn][maxn];
struct P
{
    string like,dislike;
}pl[555];
string s1;
string s2;
int getnum(int x)
{
    for(int i=1;i<=aln;i++)
    {
        if(!vis[i]&&map[x][i])
        {
            vis[i]=1;
            if(!link[i]||getnum(link[i]))
            {
                link[i]=x;
                //count+=map[x][i];
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int a,b;
    while(scanf("%d%d%d",&n,&m,&p)!=EOF)
    {
        //aln=m+n;
        aln=p;
        for(int i=1;i<=p;i++)
        {
            cin>>s1>>s2;
            pl[i].like=s1;
            pl[i].dislike=s2;
        }
        /*
        for(int i=1;i<=p;i++)
        {
            cout<<pl[i].like<<" "<<pl[i].dislike<<endl;
        }
        */
        memset(map,0,sizeof(map));
        for(int i=1;i<=p;i++)
        {
            for(int j=1;j<=p;j++)
            {
                if(pl[i].dislike==pl[j].like||pl[i].like==pl[j].dislike)
                {
                    map[i][j]=1;
                }
            }
        }
        count=0;
        memset(link,0,sizeof(link));
        for(int i=1;i<=aln;i++)
        {
            memset(vis,0,sizeof(vis));
            if(getnum(i))
            count++;
        }
        printf("%d\n",aln-count/2);
    }
    return 0;
}

1005:

hdu1569

看了别人的代码,感觉网络流不会就没写了。

http://blog.csdn.net/l04205613/article/details/6830224

1006:

hdu1350:http://acm.hdu.edu.cn/showproblem.php?pid=1350

最大路径覆盖=n/2-二分匹配

每个车为一个点,求最大路径覆盖。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define maxn 555
using namespace std;
struct P
{
    int s,e;
    int x1,y1,x2,y2;
}pl[maxn];
int map[maxn][maxn];
int vis[maxn],link[maxn];
int m;
int len(int x1,int y1,int x2,int y2)
{
    x1=x1>x2?x1-x2:x2-x1;
    y1=y1>y2?y1-y2:y2-y1;
    return x1+y1;
}
bool getnum(int x)
{
    for(int i=1;i<=m;i++)
    {
        if(!vis[i]&&map[x][i])
        {
            vis[i]=1;
            if(!link[i]||getnum(link[i]))
            {
                link[i]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int t,mi,d;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d:%d",&d,&mi);
            scanf("%d%d%d%d",&pl[i].x1,&pl[i].y1,&pl[i].x2,&pl[i].y2);
            pl[i].s=d*60+mi;
            pl[i].e=pl[i].s+len(pl[i].x1,pl[i].y1,pl[i].x2,pl[i].y2);
        }
        memset(map,0,sizeof(map));
        for(int i=1;i<=m;i++)
        {
            for(int j=i+1;j<=m;j++)
            {
                if(pl[i].e+len(pl[i].x2,pl[i].y2,pl[j].x1,pl[j].y1)<pl[j].s)
                map[i][j]=1;
            }
        }
        int count=0;
        memset(link,0,sizeof(link));
        for(int i=1;i<=m;i++)
        {
            memset(vis,0,sizeof(vis));
            if(getnum(i))
            count++;
        }
        printf("%d\n",m-count);
    }
}
1007:

hdu1151:最大路径匹配

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<queue>
#define INF 0x7fffffff
#define maxn 125
#define maxl 0x7fffffff
#define fi for(int i=0;i<n;i++)
#define fj for(int j=0;j<n;j++)
#define wh while(t--)
using namespace std;
int map[maxn][maxn];
int vis[maxn],link[maxn];
int n,m;
void init()
{
    memset(link,-1,sizeof(link));
    memset(map,0,sizeof(map));
}
bool getnum(int x)
{
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]&&map[x][i])
        {
            vis[i]=1;
            if(link[i]==-1||getnum(link[i]))
            {
                link[i]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int a,b,t;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d",&n);
        scanf("%d",&m);
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            map[a][b]=1;
        }
        int count=0;
        for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof(vis));
            if(getnum(i))
            count++;
        }
        printf("%d\n",n-count);
    }
    return 0;
}






你可能感兴趣的:(二分图匹配)