• pku 2446 && pku 1719


    都是求最大二分匹配的题目,只不过比模板题稍微灵活了一点,需要将题目进行一定的转化

    pku2446

    【题目大意】: rc列的棋盘,现在要用1x2的骨牌来覆盖整个棋盘。骨牌不能重叠,且棋盘上有的方格不能放骨牌。问能不能将棋盘完全覆盖

    【算法分析】:关键是建立二分的模型,用1x2的骨牌来覆盖棋盘其实隐含了一个性质,一张骨牌覆盖相邻的方格。就是说一次我们选择了两个方格,这两个方格相邻。把棋盘画成黑白棋盘,就转换成了二分图。每个方格可以和周围几个方格连线,寻找到最大的匹配数。比较最大匹配数*2是否和之前的空白方格数相等。另外可以发现一个剪枝,空白方格如果是奇数个,就肯定不能覆盖。

     

    pku2446
    #include<iostream>
    using namespace std;
    char g[40][40];
    char mat[1155][1155];
    int my[1155];
    char vstd[1155];
    int nx, ny;
    int dir[4][2] = {{-1, 0},{0, 1},{1, 0},{0, -1}};
    int nr, nc, nh;
    int path(int s)
    {
    int e;
    for(e = 1; e <= nr*nc; e++)
    {
    if(mat[s][e] && !vstd[e])
    {
    vstd[e]
    = 1;
    if(my[e]==-1 || path(my[e]))
    {
    my[e]
    = s;
    return 1;
    }
    }
    }
    return 0;
    }
    int MaxMatch()
    {
    int res = 0;
    for(int i = 1; i <= nr*nc; i++)
    {
    memset(vstd,
    0, sizeof(vstd));
    res
    += path(i);
    }
    return res;
    }
    int main()
    {
    scanf(
    "%d %d %d", &nr, &nc, &nh);
    int i, j, k, ni, nj, x, y;
    memset(g,
    1, sizeof(g));
    memset(mat,
    0, sizeof(mat));
    for(i = 1; i <= nh; i++)
    {
    scanf(
    "%d %d", &y, &x);
    g[x][y]
    = 0;
    }
    nx
    = 0;
    ny
    = 0;
    memset(my,
    -1, sizeof(my));
    for(i = 1; i <= nr; i++)
    {
    for(j = 1; j <= nc; j++)
    {
    if((i+j)%2==1 && g[i][j]==1)ny++;
    if((i+j)%2==0 && g[i][j]==1)
    {
    nx
    ++;
    for(k = 0; k < 4; k++)
    {
    ni
    = i+dir[k][0];
    nj
    = j+dir[k][1];
    if(g[ni][nj]==1 && ni>=1 && ni<=nr && nj>=1 && nj<=nc)
    {
    mat[(i
    -1)*nc+j][(ni-1)*nc+nj] = 1;
    if(!my[(ni-1)*nc+nj])
    my[(ni
    -1)*nc+nj]=(i-1)*nc+j;

    }
    }
    }
    }
    }
    if(nx!=ny)
    puts(
    "NO");
    else
    {
    int res = MaxMatch();
    if(res == nx)
    puts(
    "YES");
    else
    puts(
    "NO");
    }
    return 0;
    }

     

     

    pku1719

    【题目大意】:

    一个rc列的棋盘,每列中有2个白色方格和r-2个黑色方格,问你能否在每一列选出一个白色方格,共c个方格,使得这c个方格没有两个在同一行?如果能,输出方案。否则输出“NO”

    PS:刚才连题意都看不懂,太吭人了

    【算法分析】:棋盘类的另一种二分方法是行列二分,即把行看做一方,列看做一方。这道题是要选出来的白格没有两个同行。可以算行列的二分匹配,求出来的最大匹配,如果等于c,说明选出来的格子都不在同行同列。如果有两个不同列的白格不得不在同行,那么算出来的最大匹配小于c。最后输出方案,就利用匈牙利算法保存的mx[]求出具体方格。

    注意:最后在输出的时候要特别注意,题目要求输出的顺序,是按照连续的列输出的,而是在用匈牙利算法时,是为每一行找一个可匹配的列,所以并非所有列都有匹配,而对于还没有匹配的列,可以和任意满足条件的行匹配(其实,我也不知道为什么,求解释^-^)

    pku1719
    #include<iostream>
    using namespace std;
    char mat[1005][1005];
    int nx, ny;
    int match[1005];
    char vstd[1005];
    int path(int s)
    {
    int e;
    for(e = 1; e <= ny; e++)
    {
    if(mat[s][e] && !vstd[e])
    {
    vstd[e]
    = 1;
    if(match[e]==-1 || path(match[e]))
    {
    match[e]
    = s;
    return 1;
    }
    }
    }
    return 0;
    }
    int MaxMatch()
    {
    int s, res = 0;
    for(s = 1; s <= nx; s++)
    {
    memset(vstd,
    0, sizeof(vstd));
    res
    += path(s);
    }
    return res;
    }
    int main()
    {
    int cas;
    int i, j;
    int e1, e2;
    scanf(
    "%d", &cas);
    while(cas--)
    {
    scanf(
    "%d %d", &nx, &ny);
    memset(mat,
    0, sizeof(mat));
    memset(match,
    -1, sizeof(match));
    for(i = 1; i <= ny; i++)
    {
    scanf(
    "%d %d", &e1, &e2);
    mat[e1][i]
    = 1;
    mat[e2][i]
    = 1;
    }
    if(ny < nx)
    {
    printf(
    "NO\n");
    continue;
    }
    int res = MaxMatch();
    if(res == nx)
    {
    int k = 0;
    for(i = 1; i <= ny; i++)
    {
    if(match[i]==-1)
    {
    for(j = 1; j <= nx; j++)
    {
    if(mat[j][i]==1)
    {
    if(k == 0)
    {printf(
    "%d", j);k++;}
    else printf(" %d", j);
    break;
    }
    }
    }
    else
    {
    if(k == 0){printf("%d", match[i]);k++;}
    else printf(" %d", match[i]);
    }
    }
    printf(
    "\n");
    }
    else
    printf(
    "NO\n");
    }
    return 0;
    }
  • 相关阅读:
    k6负载测试学习知识
    52条SQL语句性能优化策略(转)
    JVM学习
    jsonp劫持
    Airtest API精讲之keyevent()
    Airtest API精讲之Android自定义手势
    Airtest API精讲之text()
    Airtest之调用其他脚本——using()如何使用
    Airtest API精讲之wait(),exists()
    Airtest API精讲之报告日志log()
  • 原文地址:https://www.cnblogs.com/nanke/p/2150099.html
Copyright © 2020-2023  润新知