二分图入门题集

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

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\n",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",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

 

转载于:https://www.cnblogs.com/shangyu/p/3556235.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值