zoukankan      html  css  js  c++  java
  • 二分图入门题集

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

    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
  • 相关阅读:
    数据库表结构变动发邮件脚本
    .net程序打包部署
    无法登陆GitHub解决方法
    netbeans 打包生成 jar
    第一次值班
    RHEL6 纯命令行文本界面下安装桌面
    C语言中格式化输出,四舍五入类型问题
    I'm up to my ears
    How to boot ubuntu in text mode instead of graphical(X) mode
    the IP routing table under linux@school
  • 原文地址:https://www.cnblogs.com/shangyu/p/3556235.html
Copyright © 2011-2022 走看看