• 二分图最大匹配


    HDU 1150:

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

      最小覆盖点 == 最大匹配数(选取最少的点数,使这些点和所有的边都有关联——把所有的边的覆盖)

          两台机器,有n和m个工作模式,起始工作模式都为0,现在有k件工作,第i件工作可分别在两个机器上用各自的模式工作,但换模式要重启,问重启的最小次数。

          写的时候因为是找二分最大匹配的题目时找到写的,想到了二分上去,也知道是求最小覆盖点 == 最大匹配数,但不是很能理解,先把代码写了再说。

          写的时候注意起始模式是0,所以换模式时把0的排除再外。(因为这个原因错了很多次)

    一:邻接阵做法

    代码
    #include<iostream>
    using namespace std;

    int n,m,k;
    int map[105][105]; //记录X,Y对应点可否连接
    int vis[105]; //每次找增广路时对Y中点是否访问
    int dir[105]; //Y中点匹配的X中点的位置

    int find(int a)
    {
    int i;
    for(i=0;i<m;i++)
    {
    if(map[a][i]==1 && vis[i] == 0)
    {
    vis[i]
    = 1;
    if(dir[i] == -1 || find(dir[i]))
    {
    dir[i]
    = a;
    return 1;
    }
    }
    }
    return 0;
    }

    int main()
    {
    int i,x,y;
    while(scanf("%d",&n)!=EOF && n!=0)
    {
    memset(map,
    0,sizeof(map));
    memset(dir,
    -1,sizeof(dir));
    scanf(
    "%d%d",&m,&k);
    while(k--)
    {
    scanf(
    "%d%d%d",&i,&x,&y);
    if(x && y)
    map[x][y]
    = 1; //应该不能再用map[y][x] = 1
    }
    int sum = 0;
    for(i=0;i<n;i++)
    {
    memset(vis,
    0,sizeof(vis));
    if(find(i))
    sum
    ++;
    }

    printf(
    "%d\n",sum);
    }
    return 0;
    }

    二:动态邻接表做法.

    代码
    #include<iostream>
    using namespace std;

    int n,m,k;
    int vis[105]; //每次找增广路时对Y中点是否访问
    int dir[105]; //Y中点匹配的X中点的位置

    struct edge
    {
    int from;
    int to;
    edge
    * next;
    edge()
    {
    from
    = to = 0;
    next
    = NULL;
    }
    };
    edge
    * List[105];

    void add_edge(int f,int t)
    {
    edge
    * node = new edge();
    node
    ->from = f;
    node
    ->to = t;
    node
    ->next = List[f];
    List[f]
    = node;
    }

    int find(edge* node)
    {
    while(1)
    {
    if(node == NULL)
    {
    break;
    }
    int i = node->to;
    if(vis[i] == 0)
    {
    vis[i]
    = 1;
    if(dir[i] == -1 || find(List[dir[i]]))
    {
    dir[i]
    = node->from;
    return 1;
    }
    }
    node
    = node->next;
    }
    return 0;
    }

    int main()
    {
    int i,x,y;
    while(scanf("%d",&n)!=EOF && n!=0)
    {
    for(i=0;i<=n;i++)//链表清空,一开始没清空,错了很多次
    {
    List[i]
    = NULL;
    }
    memset(dir,
    -1,sizeof(dir));
    scanf(
    "%d%d",&m,&k);
    while(k--)
    {
    scanf(
    "%d%d%d",&i,&x,&y);
    if(x && y)
    add_edge(x,y);
    }
    int sum = 0;
    for(i=1;i<=n;i++)
    {
    memset(vis,
    0,sizeof(vis));
    if(find(List[i]))
    sum
    ++;
    }
    printf(
    "%d\n",sum);
    }
    return 0;
    }

    HDU 1151:

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

         最小路径覆盖(选取最少的边覆盖所有的点) == 节点数 - 最大匹配数


    代码
    #include <iostream>
    using namespace std;
    #define MAXN 125

    int vis[MAXN];
    int link[MAXN];
    int n,m;

    struct edge
    {
    int from;
    int to;
    edge
    * next;
    edge()
    {
    from
    = to = 0;
    next
    = NULL;
    }
    };
    edge
    * List[MAXN];

    void add_edge(int f,int t)
    {
    edge
    * node = new edge();
    node
    ->from = f;
    node
    ->to = t;
    node
    ->next = List[f];
    List[f]
    = node;
    }

    bool find(edge* node)
    {
    while(1)
    {
    if(node == NULL)
    break;
    int i = node->to;
    if(vis[i] == 0)
    {
    vis[i]
    = 1;
    if(link[i] == 0 || find(List[link[i]]))
    {
    link[i]
    = node->from;
    return 1;
    }
    }
    node
    = node->next;
    }

    return 0;
    }

    int main()
    {
    int i;
    int t,x,y;
    scanf(
    "%d",&t);
    while(t--)
    {
    memset(link,
    0,sizeof(link));
    scanf(
    "%d%d",&n,&m);
    for(i=0;i<=n;i++)
    {
    List[i]
    = NULL;
    }
    for(i=0;i<m;i++)
    {
    scanf(
    "%d%d",&x,&y);
    add_edge(x,y);
    }
    int sum = 0;
    for(i=1;i<=n;i++)
    {
    memset(vis,
    0,sizeof(vis));
    if(find(List[i]))
    sum
    ++;
    }

    printf(
    "%d\n",n-sum);
    }
    return 0;
    }

     

    HDU 1068:

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

      二分图最大独立集=顶点数-二分图最大匹配

    代码
    #include <iostream>
    using namespace std;

    const long max_edge = 100005;
    const long max_point = 1005;
    int n;
    int Index;

    struct node
    {
    int y;
    int next;
    }stu[max_edge];
    int pre[max_point];//以该点为起点的第一条在stu中的存储位置
    int vis[max_point];//Y中结点的访问情况
    int link[max_point];//Y中与X中配对的情况

    void add_edge(int a,int b)
    {
    stu[Index].y
    = b;
    stu[Index].next
    = pre[a];
    pre[a]
    = Index++;
    }

    void Init()
    {
    int i,j,s,t,m;
    char c;

    Index
    = 1;
    memset(pre,
    -1,sizeof(pre));
    memset(link,
    -1,sizeof(link));

    for(i=0;i<n;i++)
    {
    cin
    >>s>>c>>c>>m>>c;
    for(j=0;j<m;j++)
    {
    scanf(
    "%d",&t);
    add_edge(s,t);
    }
    }
    }

    bool find(int dir)
    {
    int i;
    for(i=pre[dir]; i!=-1; i=stu[i].next)
    {
    int ii = stu[i].y;
    if(vis[ii] == 0)
    {
    vis[ii]
    = 1;
    if(link[ii] == -1 || find(link[ii]))
    {
    link[ii]
    = dir;
    return true;
    }
    }
    }

    return false;
    }

    void Play()
    {
    int i;
    int ans = 0;
    for(i=0;i<n;i++)
    {
    memset(vis,
    0,sizeof(vis));
    if(find(i))
    ans
    ++;
    }

    printf(
    "%d\n",n-ans/2);
    }
    int main()
    {
    while(scanf("%d",&n)!=EOF)
    {
    Init();
    Play();
    }
    return 0;
    }

    HDU 1281:

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

    写的时候写搓了,一个小错误,find1递归的时候用了find函数,很是郁闷!

    当数据量小的时候可以不用静态连接表存储,毕竟连接阵用起来比连接表方便!

    代码
    #include <iostream>
    using namespace std;

    const long max_point = 1005;
    const long max_edge = 100005;

    int n,m,k;
    int cas = 0;
    int mat[max_point][max_point];
    int vis[max_point];
    int linky[max_point];
    int linkx[max_point];

    void Init()
    {
    int i;
    int a,b;
    memset(mat,
    0,sizeof(mat));

    for(i=0;i<k;i++)
    {
    scanf(
    "%d%d",&a,&b);
    mat[a][b]
    = 1;
    }
    }

    bool find(int dir,bool flag)
    {
    int i;
    for(i=1;i<=m;i++)
    {
    if(mat[dir][i] && !vis[i])
    {
    vis[i]
    = 1;
    if(linky[i]==-1 || find(linky[i],flag))
    {
    if(flag)
    {
    linkx[dir]
    = i;
    linky[i]
    = dir;
    }
    return true;
    }
    }
    }

    return false;
    }

    bool can()
    {
    int i;
    for(i=1;i<=n;i++)
    {
    if(linkx[i] == -1)
    {
    memset(vis,
    0,sizeof(vis));
    if(find(i,0))
    {
    return true;
    }
    }
    }

    return false;
    }
    void Play()
    {
    int i,j;

    int ans = 0;
    memset(linkx,
    -1,sizeof(linkx));
    memset(linky,
    -1,sizeof(linky));
    for(i=1;i<=n;i++)
    {
    memset(vis,
    0,sizeof(vis));
    if(find(i,1))
    ans
    ++;
    }

    int ans1 = 0;
    for(i=1;i<=n;i++)
    {
    if(linkx[i] != -1)
    {
    int tmp = linkx[i];
    linkx[i]
    = -1;
    linky[tmp]
    = -1;
    mat[i][tmp]
    = 0;

    if(!can())
    ans1
    ++;

    mat[i][tmp]
    = 1;
    linky[tmp]
    = i;
    linkx[i]
    = tmp;
    }
    }

    printf(
    "Board %d have %d important blanks for %d chessmen.\n",++cas,ans1,ans);
    }

    int main()
    {
    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
    Init();
    Play();
    }
    return 0;
    }

    HDU 1498:

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

    感觉来了,这题没花什么精力,一杯咖啡的时候想了出来。对每个颜色,求最小点覆盖,如果大于k,则不能在k时间内完成,输出;否则可以完成。

    代码
    #include <iostream>
    using namespace std;

    int n,k;
    const long max_color = 55;
    const long maxn = 105;
    int Hash[max_color];
    int map[max_color][maxn][maxn];
    int vis[maxn];
    int linkx[maxn],linky[maxn];

    void Init()
    {
    int i,j;

    memset(map,
    0,sizeof(map));
    memset(Hash,
    0,sizeof(Hash));

    for(i=0;i<n;i++)
    {
    for(j=0;j<n;j++)
    {
    int color;
    scanf(
    "%d",&color);
    map[color][i][j]
    = 1;
    Hash[color]
    = 1;
    }
    }
    }

    bool find(int dir,int u)
    {
    int i,j;
    for(i=0;i<n;i++)
    {
    if(1 == map[dir][u][i])
    {
    if(0 == vis[i])
    {
    vis[i]
    = 1;
    if(linky[i] == -1 || find(dir,linky[i]))
    {
    linky[i]
    = u;
    linkx[u]
    = i;
    return true;
    }
    }
    }
    }

    return false;
    }
    int MaxMatch(int dir)
    {
    int i;
    int sum = 0;
    memset(linkx,
    -1,sizeof(linkx));
    memset(linky,
    -1,sizeof(linky));

    for(i=0;i<n;i++)
    {
    if(-1 == linkx[i])
    {
    memset(vis,
    0,sizeof(vis));
    if(find(dir,i))
    {
    sum
    ++;
    }
    }
    }

    return sum;
    }

    void Play()
    {
    int i;
    int flag = 0;
    for(i=1;i<=50;i++)
    {
    //对应每种颜色
    if(1 == Hash[i])
    {
    int num = MaxMatch(i);

    /*if(flag != 0)
    {//这个放在外面,PE了一次
    printf(" ");
    }
    */

    if(num > k)
    {
    if(flag != 0)
    {
    printf(
    " ");
    }
    printf(
    "%d",i);
    flag
    = 1;
    }
    }
    }

    if(0 == flag)
    {
    printf(
    "-1");
    }

    printf(
    "\n");
    }

    int main()
    {
    while(scanf("%d%d",&n,&k)!=EOF && (n!=0 || k!=0))
    {
    Init();
    Play();
    }
    return 0;
    }

    HDU 1528:

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

    简单题,卡片为点,大小关系为边,求最大匹配。 

    代码
    #include <iostream>
    #include
    <map>
    using namespace std;
    const long maxn = 30;

    int k;
    map
    <char,int> M;
    int num_Adam[maxn],num_Eve[maxn];
    int linkx[maxn],linky[maxn];
    int mat[maxn][maxn],vis[maxn],pre[maxn];

    void Init()
    {
    int i,j;
    char c1,c2;
    memset(mat,
    0,sizeof(mat));

    M[
    '2'] = 0;M['3'] = 1;M['4'] = 2;M['5'] = 3;M['6'] = 4;
    M[
    '7'] = 5;M['8'] = 6;M['9'] = 7;M['T'] = 8;M['J'] = 9;
    M[
    'Q'] = 10;M['K'] = 11;M['A'] = 12;
    M[
    'H'] = 3;M['S'] = 2;M['D'] = 1;M['C'] = 0;


    scanf(
    "%d",&k);
    for(i=0;i<k;i++)
    {
    cin
    >>c1>>c2;
    num_Adam[i]
    = M[c1] * 4 + M[c2];
    }
    for(i=0;i<k;i++)
    {
    cin
    >>c1>>c2;
    num_Eve[i]
    = M[c1] * 4 + M[c2];
    }

    for(i=0;i<k;i++)
    {
    for(j=0;j<k;j++)
    {
    if(num_Adam[i] < num_Eve[j])
    {
    mat[i][j]
    = 1;
    }
    }
    }
    }

    bool find(int dir)
    {
    int i;
    for(i=0;i<k;i++)
    {
    if(1 == mat[dir][i] && 0 == vis[i])
    {
    vis[i]
    = 1;
    if(linky[i] == -1 || find(linky[i]))
    {
    linky[i]
    = dir;
    linkx[dir]
    = i;
    return true;
    }
    }
    }

    return false;
    }

    void Play()
    {
    int i;
    int ans = 0;
    memset(linkx,
    -1,sizeof(linkx));
    memset(linky,
    -1,sizeof(linky));

    for(i=0;i<k;i++)
    {
    if(-1 == linkx[i])
    {
    memset(vis,
    0,sizeof(vis));
    if(find(i))
    ans
    ++;
    }
    }

    printf(
    "%d\n",ans);
    }

    int main()
    {
    int t;
    scanf(
    "%d",&t);
    while(t--)
    {
    Init();
    Play();
    }
    return 0;
    }
  • 相关阅读:
    用C#一次匹配HTML代码中A的链接和文字的方法
    去黑头的7个必胜秘方
    用C#写外挂或辅助工具必须要的WindowsAPI
    用C#把HTML内容转为UBB的方法
    Windows Server 2008 Standard, Enterprise, and Datacenter with Service Pack 2
    xmpp协议分析
    查看Win7的真实版本号方法
    什么是游戏NP?如何在NP下读写游戏内存及如何进入NP进程
    C#正则表达式扫盲 保证 10分钟入门 30分钟精通[绝对不可错过的文章]
    可扩展消息出席协议(XMPP):核心 RFC 3920
  • 原文地址:https://www.cnblogs.com/silencExplode/p/1896036.html
Copyright © 2020-2023  润新知