最近遇到二分图匹配的题目,发现不怎么会,重新把之前的题目看了看,做下总结吧。
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 }
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 }
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 }
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 }
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 **************************************/