zoukankan      html  css  js  c++  java
  • pku 1486 求出二分匹配图中的必须边

    开始楞是没看懂意思,E文让我很纠结...

    要判断一条边是否为二分图中必须边,方法如下:

    1、先求出原图的任意最大匹配

    2、对二分图某一边的所有点,删去其当前的匹配边。删的过程不是简单的将原图设为不连通,你还得将其相应的匹配值设为未匹配。

    假如原图link[a]=b;  那我们删边的时候既要讲map[b][a]设为0.,同时也要讲link[a]设为-1。(举个例子而已,数据的写法自己定)

    3、对此跟新图再次从b点(承接上面的例子)进行一次最大匹配,如果此时还能完成最大匹配,那么刚才删去的那条边显然就不是必须边了。反之,必须边成立!(做完记得将图还原)

    4、重复2步骤,直到所有的点都被删过了一次当前匹配边

    (还有一个问题就是,再对跟新图进行最大匹配验证的过程中,这必然不可避免的会改变其他匹配边原来的信息。比如a点原来匹配着b点,在新方案中,它可能却变成了匹配c点。其实这对我们的算法没有任何影响,因为我们本来的目的就只是对点进行匹配,至于该点和那个点匹配,无所谓。最开始,我们也是任意的进行了一次二分匹配。我们删边的目的只是为了验证该点是不是还存在着其他匹配方案,至于是从哪一个方案变到哪一个方案,没有任何关系)

    View Code
    #include<iostream>
    #include
    <string>
    using namespace std;

    int link[30];
    int map[30][30];
    typedef
    struct node
    {
    int xmin;
    int xmax;
    int ymin;
    int ymax;
    }node;

    node num[
    30];
    int n,m;
    int v[30];

    int find(int x)
    {
    for(int i=1;i<=n;i++)
    {
    if(!v[i] && map[x][i])
    {
    v[i]
    =1;
    if(link[i]==0 || find(link[i]))
    {
    link[i]
    =x;
    return 1;
    }
    }
    }
    return 0;
    }

    void solve()
    {
    int i;
    memset(link,
    0,sizeof(link));
    for(i=1;i<=n;i++)
    {
    memset(v,
    0,sizeof(v));
    find(i);
    }
    }


    int isok(int x,int y,int i)
    {
    if(x>=num[i].xmin && x<=num[i].xmax && y>=num[i].ymin && y<=num[i].ymax)
    return 1;
    return 0;
    }

    int main()
    {
    int i,j,a,b;m=1;
    freopen(
    "D:\\in.txt","r",stdin);
    while(scanf("%d",&n),n)
    {
    for(i=1;i<=n;i++)
    {
    scanf(
    "%d%d%d%d",&num[i].xmin,&num[i].xmax,&num[i].ymin,&num[i].ymax);
    }
    memset(map,
    0,sizeof(map));
    for(i=1;i<=n;i++)
    {
    scanf(
    "%d%d",&a,&b);
    for(j=1;j<=n;j++)
    {
    if(isok(a,b,j))
    {
    map[i][j]
    =1; //左边代表数字,右边代表字母
    }
    }
    }

    //先任意求一次最大匹配
    solve();
    printf(
    "Heap %d\n",m++);
    int flag=0;
    for(i=1;i<=n;i++)
    {
    if(!link[i])
    continue;
    int temp=link[i];
    link[i]
    =0; //把位置腾出来
    map[temp][i]=0; //同时把边删掉,这样就无法达到原来的匹配
    memset(v,0,sizeof(v));
    if(!find(temp)) //如果没有新的匹配方案诞生,说明这是一条关键边
    {
    if(flag)
    cout
    <<" ";
    flag
    =1;
    link[i]
    =temp;
    printf(
    "(%c,%d)",(char)(i+64),temp);
    }
    map[temp][i]
    =1; //把图复原
    }
    if(!flag)
    {
    cout
    <<"none";
    }
    cout
    <<endl<<endl;
    }
    return 0;
    }
  • 相关阅读:
    牛牛与LCM(最小公约数)
    小明的挖矿之旅_牛客网(思维题)
    2019/4/20周赛 F题 CodeForces
    哥德巴赫猜想_2019/7/11_牛客网
    智障操作-wireless AC 9462
    codeforces762A
    2019中山大学程序设计竞赛(重现赛)斐波那契/
    Java自学笔记(10):【面向对象 】 类和对象、构造方法、this关键字
    Java自学笔记(9):方法
    Java自学笔记(8):多维数组
  • 原文地址:https://www.cnblogs.com/ka200812/p/2121866.html
Copyright © 2011-2022 走看看