• 二分图入门题集


    最近遇到二分图匹配的题目,发现不怎么会,重新把之前的题目看了看,做下总结吧。

    http://poj.org/problem?id=1469  纯纯的二分图的最大匹配

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<queue>
     8 #include<cmath>
     9 using namespace std;
    10 vector<int>pa[410];
    11 int vis[410],mat[410];
    12 int find(int u)
    13 {
    14     int i;
    15     for(i = 0 ; i < (int)pa[u].size() ; i++)
    16     {
    17         int v = pa[u][i];
    18         if(vis[v]) continue;
    19         vis[v] = 1;
    20         if(mat[v]==0||find(mat[v]))
    21         {
    22             mat[v] = u;
    23             return 1;
    24         }
    25     }
    26     return 0;
    27 }
    28 int main()
    29 {
    30     int t,n,m,i,j;
    31     cin>>t;
    32     while(t--)
    33     {
    34         memset(mat,0,sizeof(mat));
    35         for(i = 1; i <= 400 ; i++)
    36         pa[i].clear();
    37         scanf("%d%d",&m,&n);
    38         for(i = 1; i <= m ;i++)
    39         {
    40             int k,u;
    41             scanf("%d",&k);
    42             for(j = 1; j <= k ;j++)
    43             {
    44                 scanf("%d",&u);
    45                 pa[i].push_back(m+u);
    46             }
    47         }
    48         int s=0;
    49         for(i = 1; i <= m ;i++)
    50         {
    51             memset(vis,0,sizeof(vis));
    52             if(find(i))
    53             s++;
    54         }
    55         if(s==m)
    56         puts("YES");
    57         else
    58         puts("NO");
    59     }
    60     return 0;
    61 }
    View Code

    http://poj.org/problem?id=3041 纯纯的最小点覆盖 把点拆成边  用最少的点覆盖所有的边

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<queue>
     8 #include<cmath>
     9 using namespace std;
    10 #define N 1010
    11 vector<int>pa[N];
    12 bool f[N];
    13 int vis[N],mat[N];
    14 int find(int u)
    15 {
    16     int i;
    17     for(i = 0 ; i < (int)pa[u].size() ; i++)
    18     {
    19         int v = pa[u][i];
    20         if(vis[v]) continue;
    21         vis[v] = 1;
    22         if(mat[v]==0||find(mat[v]))
    23         {
    24             mat[v] = u;
    25             return 1;
    26         }
    27     }
    28     return 0;
    29 }
    30 int main()
    31 {
    32     int n,m,i;
    33     while(scanf("%d%d",&n,&m)!=EOF)
    34     {
    35         memset(mat,0,sizeof(mat));
    36         memset(f,0,sizeof(f));
    37         for(i = 1; i <= 1000 ; i++)
    38         pa[i].clear();
    39         for(i = 1; i <= m ;i++)
    40         {
    41             int v,u;
    42             scanf("%d%d",&u,&v);
    43             pa[u].push_back(v);
    44             f[u] = 1;
    45         }
    46         int s=0;
    47         for(i = 1; i <= n ;i++)
    48         {
    49             if(!f[i]) continue;
    50             memset(vis,0,sizeof(vis));
    51             if(find(i))
    52             s++;
    53         }
    54         printf("%d
    ",s);
    55     }
    56     return 0;
    57 }
    View Code

    http://poj.org/problem?id=1422 纯纯的最小路径覆盖 总结点-最大匹配

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<queue>
     8 #include<cmath>
     9 using namespace std;
    10 #define N 1010
    11 vector<int>pa[N];
    12 bool fx[N],fy[N];
    13 int vis[N],mat[N];
    14 int find(int u)
    15 {
    16     int i;
    17     for(i = 0 ; i < (int)pa[u].size() ; i++)
    18     {
    19         int v = pa[u][i];
    20         if(vis[v]) continue;
    21         vis[v] = 1;
    22         if(mat[v]==0||find(mat[v]))
    23         {
    24             mat[v] = u;
    25             return 1;
    26         }
    27     }
    28     return 0;
    29 }
    30 int main()
    31 {
    32     int n,m,i,t;
    33     scanf("%d",&t);
    34     while(t--)
    35     {
    36         scanf("%d%d",&n,&m);
    37         memset(mat,0,sizeof(mat));
    38         for(i = 1; i <= 1000 ; i++)
    39         pa[i].clear();
    40         for(i = 1; i <= m ;i++)
    41         {
    42             int v,u;
    43             scanf("%d%d",&u,&v);
    44             pa[u].push_back(v+n);
    45         }
    46         int s = 0;
    47         for(i = 1; i <= n ;i++)
    48         {
    49             memset(vis,0,sizeof(vis));
    50             if(find(i))
    51                 s++;
    52         }
    53         printf("%d
    ",n-s);
    54     }
    55     return 0;
    56 }
    View Code

    http://poj.org/problem?id=3020 这题可以最小路径来做

    以前拆点做的 这次没有拆点 直接找最大匹配 以为一根天线覆盖2点 正好是一对匹配 所以最大的匹配的时候肯定是用天线最少的时候 ans = 总结点-2*最大匹配+最大匹配

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<cmath>
     7 #include<vector>
     8 using namespace std;
     9 char c[42][12];
    10 vector<int>pa[410];
    11 int vis[420],vv[420],mat[420];
    12 int find(int u)
    13 {
    14     int i;
    15     for(i = 0 ;i < (int)pa[u].size() ; i++)
    16     {
    17         int v = pa[u][i];
    18         if(vv[v]) continue;
    19         vv[v] = 1;
    20         if(mat[v]==0||find(mat[v]))
    21         {
    22             mat[v] = u;
    23             return 1;
    24         }
    25     }
    26     return 0;
    27 }
    28 void dfs(int u,int f)
    29 {
    30     vis[u] = f;
    31     int i;
    32     for(i = 0 ;i < (int)pa[u].size(); i++)
    33     {
    34         int v = pa[u][i];
    35         if(vis[v]) continue;
    36         dfs(v,f*(-1));
    37     }
    38 }
    39 int main()
    40 {
    41     int n,i,j,w,h;
    42     cin>>n;
    43     while(n--)
    44     {
    45         memset(c,0,sizeof(c));
    46         memset(vis,0,sizeof(vis));
    47         memset(vv,0,sizeof(vv));
    48         memset(mat,0,sizeof(mat));
    49         memset(pa,0,sizeof(pa));
    50         cin>>w>>h;
    51         for(i =1; i <= w ; i++)
    52             for(j = 1; j <= h ; j++)
    53             cin>>c[i][j];
    54         int s=0;
    55         for(i = 1; i <= w ; i++)
    56             for(j = 1 ; j <= h ; j++)
    57             {
    58                 if(c[i][j]=='*') s++;
    59                 if(c[i][j]=='*'&&c[i+1][j]=='*')
    60                     pa[(i-1)*h+j].push_back(i*h+j);
    61                 if(c[i][j]=='*'&&c[i][j+1]=='*')
    62                     pa[(i-1)*h+j].push_back((i-1)*h+j+1);
    63                 if(c[i][j]=='*'&&c[i][j-1]=='*')
    64                 pa[(i-1)*h+j].push_back((i-1)*h+j-1);
    65                 if(c[i][j]=='*'&&c[i-1][j]=='*')
    66                 pa[(i-1)*h+j].push_back((i-2)*h+j);
    67             }
    68         int ans=0;
    69         for(i = 1; i <= w ; i++)
    70             for(j = 1 ;j <= h ;j++)
    71             {
    72                 int k = (i-1)*h+j;
    73                 if(c[i][j]!='*'||vis[k]) continue;
    74                 dfs(k,1);
    75             }
    76         for(i = 1; i <= w*h ; i++)
    77         {
    78             memset(vv,0,sizeof(vv));
    79             if(vis[i]==1)
    80             {
    81                 if(find(i)) ans++;
    82             }
    83         }
    84         cout<<s-ans<<endl;
    85     }
    86     return 0;
    87 }
    View Code

    http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=1925 这是09年区域赛的一道题 是求减去最小的边使得图里没有奇圈

    这样 这题就可以利用二分图的性质来做 因为二分图是不含奇圈的 15个点 (1<<15)种分法 看哪种方法所需删边最少

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 using namespace std;
    10 #define INF 0xfffffff
    11 bool f[16];
    12 struct node
    13 {
    14     int u,v;
    15 }p[310];
    16 int main()
    17 {
    18     int t,i,j,n,m;
    19     cin>>t;
    20     while(t--)
    21     {
    22        cin>>n>>m;
    23        for(i = 1; i <= m ;i++)
    24        {
    25            cin>>p[i].u>>p[i].v;
    26        }
    27        int minz = INF;
    28        for(i = 0 ;i < (1<<n) ; i++)
    29        {
    30            int cnt=0;
    31            memset(f,0,sizeof(f));
    32            for(j = 0 ;j < n ; j++)
    33            {
    34                if(i&(1<<j))
    35                    f[j] = 1;
    36            }
    37            for(j = 1 ; j <= m ; j++)
    38            if(f[p[j].u]==f[p[j].v])
    39            cnt++;
    40            minz = min(minz,cnt);
    41        }
    42        cout<<minz<<endl;
    43     }
    44     return 0;
    45 }
    46  
    47 
    48 
    49 
    50 /**************************************
    51     Problem id    : SDUT OJ 1925 
    52     User name    : shang 
    53     Result        : Accepted 
    54     Take Memory    : 476K 
    55     Take Time    : 30MS 
    56     Submit Time    : 2014-02-19 10:51:51  
    57 **************************************/
    View Code
  • 相关阅读:
    05-----数据类型转换
    04-----赋值运算符
    03-----数据类型
    02-----第一个JavaScript代码
    Fxx and game
    Bomb
    Stammering Aliens
    DISUBSTR
    Life Forms
    后缀数组二·重复旋律2
  • 原文地址:https://www.cnblogs.com/shangyu/p/3556235.html
Copyright © 2020-2023  润新知