wenbao与二分图
-----------------------------
http://acm.hdu.edu.cn/showproblem.php?pid=2063
1 #include <iostream> 2 #include <time.h> 3 #include <stdio.h> 4 #include <vector> 5 #include <string.h> 6 using namespace std; 7 const int maxn = 505; 8 int n, x, y, sum; 9 bool vis[maxn]; 10 int use[maxn]; 11 vector<int> v[maxn]; 12 bool Find(int x){ 13 for(int i = 0; i < v[x].size(); ++i){ 14 int xx = v[x][i]; 15 if(!vis[xx]){ 16 vis[xx] = true; 17 if(!use[xx] || Find(use[xx])){ 18 use[xx] = x; 19 return true; 20 } 21 } 22 } 23 return false; 24 } 25 int main(){ 26 while(scanf("%d", &n)){ 27 if(n == 0) break; 28 scanf("%d%d", &x, &y); 29 int sum = 0; 30 memset(use, 0, sizeof(use)); 31 for(int i = 0; i < n; ++i){ 32 int xx, yy; 33 scanf("%d%d", &xx, &yy); 34 v[xx].push_back(yy); 35 } 36 for(int i = 1; i <= x; ++i){ 37 memset(vis, false, sizeof(vis)); 38 if(Find(i)) sum ++; 39 } 40 printf("%d\n", sum); 41 for(int i = 1; i <= x; ++i){ 42 v[i].clear(); 43 } 44 } 45 //printf("%.3lf\n", (double)clock()/CLOCKS_PER_SEC); 46 return 0; 47 }
--------------------------------------
http://acm.hdu.edu.cn/showproblem.php?pid=1150
konig定理
二分图:
顶点可以分类两个集合X和Y,所有的边关联在两个顶点中,恰好一个属于集合X,另一个属于集合Y。
最小覆盖:
最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。可以证明:最少的点(即覆盖数)=最大匹配数
Konig定理:
二分图的最小顶点覆盖数 == 最大匹配数。
1 #include <iostream> 2 #include <ctime> 3 #include <string.h> 4 #include <vector> 5 using namespace std; 6 const int maxn = 109; 7 vector<int> v[maxn]; 8 int use[maxn]; 9 bool vis[maxn]; 10 bool Find(int x){ 11 for(int i = 0; i < v[x].size(); ++i){ 12 int xx = v[x][i]; 13 if(!vis[xx]){ 14 vis[xx] = true; 15 if(!use[xx] || Find(use[xx])){ 16 use[xx] = x; 17 return true; 18 } 19 } 20 } 21 return false; 22 } 23 int main(){ 24 int x, y, n, m, xx, yy; 25 while(scanf("%d", &x)){ 26 if(x == 0) break; 27 memset(use, 0, sizeof(use)); 28 scanf("%d%d", &y, &n); 29 for(int i = 0; i < n; ++i){ 30 scanf("%d%d%d", &m, &xx, &yy); 31 v[xx].push_back(yy); 32 } 33 int sum = 0; 34 for(int i = 1; i <= x; ++i){ 35 memset(vis, false, sizeof(vis)); 36 if(Find(i)) sum ++;// cout <<i<< "******"<<endl; 37 } 38 printf("%d\n", sum); 39 for(int i = 1; i <= x; ++i) v[i].clear(); 40 } 41 return 0; 42 }
---------------------------------------
http://acm.hdu.edu.cn/showproblem.php?pid=2119
01矩阵中求最少次数变为全为0的矩阵(可以消去一行和一列)
1 #include <iostream> 2 #include <ctime> 3 #include <vector> 4 #include <string.h> 5 using namespace std; 6 const int maxn = 105; 7 vector<int> v[maxn]; 8 int use[maxn]; 9 bool vis[maxn]; 10 bool Find(int x){ 11 for(int i = 0; i < v[x].size(); ++i){ 12 int xx = v[x][i]; 13 if(!vis[xx]){ 14 vis[xx] = true; 15 if(!use[xx] || Find(use[xx])){ 16 use[xx] = x; 17 return true; 18 } 19 } 20 } 21 return false; 22 } 23 int main(){ 24 int n, m; 25 char x; 26 while(~scanf("%d", &n) && n){ 27 scanf("%d", &m); 28 for(int i = 1; i <= n; ++i){ 29 for(int j = 1; j <= m; ++j){ 30 scanf(" %c", &x); 31 if(x == '1') v[i].push_back(j); 32 } 33 } 34 int sum = 0; 35 memset(use, 0, sizeof(use)); 36 for(int i = 1; i <= n; ++i){ 37 memset(vis, false, sizeof(vis)); 38 if(Find(i)) sum ++; 39 } 40 printf("%d\n", sum); 41 for(int i = 1; i <= n; ++i){ 42 v[i].clear(); 43 } 44 } 45 return 0; 46 }
---------------------------------------------
http://acm.hdu.edu.cn/showproblem.php?pid=4160
盒子套盒子
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 using namespace std; 5 const int maxn = 505; 6 struct Node{ 7 int x, y, z; 8 }T[maxn]; 9 int use[maxn], n; 10 bool vis[maxn]; 11 bool ok(int a, int b){ 12 if(T[a].x > T[b].x && T[a].y > T[b].y && T[a].z > T[b].z) return true; 13 return false; 14 } 15 bool Find(int x){ 16 for(int i = 1; i <= n; ++i){ 17 if(!vis[i] && ok(x, i)){ 18 vis[i] = true; 19 if(!use[i] || Find(use[i])){ 20 use[i] = x; 21 return true; 22 } 23 } 24 } 25 return false; 26 } 27 int main(){ 28 while(~scanf("%d", &n) && n){ 29 for(int i = 1; i <= n; ++i){ 30 scanf("%d%d%d", &T[i].x, &T[i].y, &T[i].z); 31 } 32 memset(use, 0, sizeof(use)); 33 int sum = 0; 34 for(int i = 1; i <= n; ++i){ 35 memset(vis, false, sizeof(vis)); 36 if(Find(i)) sum ++; 37 } 38 printf("%d\n", n-sum); 39 } 40 return 0; 41 }
----------------------------------------
http://acm.hdu.edu.cn/showproblem.php?pid=5285
带权并查集
1 #include <iostream> 2 #include <string.h> 3 #include <vector> 4 using namespace std; 5 const int maxn = 100009; 6 int T[maxn], sum[maxn], a[maxn], b[maxn][2]; 7 bool vis[maxn]; 8 int Find(int x){ 9 if(x == T[x]) return x; 10 int xx = T[x]; 11 T[x] = Find(xx); 12 sum[x] ^= sum[xx]; 13 return T[x]; 14 } 15 int main(){ 16 int t; 17 scanf("%d", &t); 18 while(t--){ 19 bool flag = true; 20 int n, m; 21 scanf("%d%d", &n, &m); 22 for(int i = 1; i <= n; ++i){ 23 T[i] = i, sum[i] = 0; 24 } 25 for(int i = 0; i < m; ++i){ 26 int x, y; 27 scanf("%d%d", &x, &y); 28 int xx = Find(x), yy = Find(y); 29 if(xx != yy){ 30 T[yy] = xx; 31 sum[yy] = sum[x]^1^sum[y]; 32 }else{ 33 if(sum[x] == sum[y]){ 34 flag = false; 35 } 36 } 37 } 38 if(!flag || n <= 1){ 39 printf("Poor wyh\n"); 40 continue; 41 } 42 if(m == 0){ 43 printf("%d 1\n", n-1); 44 continue; 45 } 46 int num = 0, mi = 0; 47 memset(vis, false, sizeof(vis)); 48 memset(b, 0, sizeof(b)); 49 for(int i = 1; i <= n; ++i){ 50 int xx = Find(i); 51 //printf("%d*******%d\n", xx, sum[i]); 52 if(!vis[xx]){ 53 vis[xx] = true; 54 a[num++] = xx; 55 } 56 b[xx][sum[i]] ++; 57 } 58 for(int i = 0; i < num; ++i){ 59 int xx = a[i]; 60 mi += min(b[xx][0], b[xx][1]); 61 //cout<<xx<<"***"<<b[xx][0]<<"****"<<b[xx][1]<<endl; 62 } 63 printf("%d %d\n", n-mi, mi); 64 } 65 return 0; 66 } 67 68 69 /* 70 5 3 71 1 2 72 1 3 73 1 4 74 */
dfs标记染色
1 #include <iostream> 2 #include <vector> 3 #include <queue> 4 #include <string.h> 5 using namespace std; 6 const int maxn = 100009; 7 vector<int> v[maxn]; 8 int num, num2, vis[maxn]; 9 bool dfs(int x){ 10 if(v[x].size() == 0) return true; 11 queue<int> q; 12 q.push(x); 13 vis[x] = 1; 14 while(!q.empty()){ 15 int y = q.front(); 16 q.pop(); 17 for(int i = 0; i < v[y].size(); ++i){ 18 int xx = v[y][i]; 19 if(vis[y] == vis[xx]) return false; 20 if(!vis[xx]){ 21 vis[xx] = vis[y] == 1 ? 2 : 1; 22 q.push(xx); 23 if(vis[xx] == 1) num ++; 24 else num2 ++; 25 } 26 } 27 } 28 return true; 29 } 30 int main(){ 31 int t; 32 scanf("%d", &t); 33 while(t--){ 34 int n, m, mi = 0; 35 scanf("%d%d", &n, &m); 36 for(int i = 0; i < m; ++i){ 37 int x, y; 38 scanf("%d%d", &x, &y); 39 v[x].push_back(y), v[y].push_back(x); 40 } 41 if(n <= 1){ 42 printf("Poor wyh\n"); 43 continue; 44 } 45 if(m == 0){ 46 printf("%d 1\n", n-1); 47 continue; 48 } 49 bool flag = true; 50 memset(vis, 0, sizeof(vis)); 51 for(int i = 1; i <= n; ++i){ 52 if(!vis[i]){ 53 num = 1, num2 = 0; 54 if(!dfs(i)){ 55 flag = false; 56 break; 57 } 58 mi += max(num, num2); 59 } 60 } 61 if(!flag){ 62 printf("Poor wyh\n"); 63 }else{ 64 printf("%d %d\n", mi, n-mi); 65 } 66 for(int i = 1; i <= n; ++i) v[i].clear(); 67 } 68 return 0; 69 }
-----------------------------------------------
http://acm.hdu.edu.cn/showproblem.php?pid=2444
判断二分图再求最大匹配
并查集判断二分图
1 #include <iostream> 2 #include <string.h> 3 #include <vector> 4 using namespace std; 5 const int maxn = 205; 6 vector<int> v[maxn]; 7 int sum[maxn], T[maxn], use[maxn]; 8 bool vis[maxn]; 9 bool FFind(int x){ 10 for(int i = 0; i < v[x].size(); ++i){ 11 int xx = v[x][i]; 12 if(!vis[xx]){ 13 vis[xx] = true; 14 if(!use[xx] || FFind(use[xx])){ 15 use[xx] = x; 16 return true; 17 } 18 } 19 } 20 return false; 21 } 22 int Find(int x){ 23 if(T[x] == x) return x; 24 int xx = T[x]; 25 T[x] = Find(xx); 26 sum[x] ^= sum[xx]; 27 return T[x]; 28 } 29 int main(){ 30 int n, m; 31 while(~scanf("%d%d", &n, &m)){ 32 for(int i = 1; i <= n; ++i) T[i] = i, sum[i] = 0, v[i].clear(); 33 bool flag = true; 34 for(int i = 0; i < m; ++i){ 35 int x, y; 36 scanf("%d%d", &x, &y); 37 if(!flag) continue; 38 int xx = Find(x), yy = Find(y); 39 if(xx != yy){ 40 T[xx] = yy; 41 sum[xx] = sum[x] ^ sum[y] ^ 1; 42 }else{ 43 if(sum[x] == sum[y]){ 44 flag = false; 45 } 46 } 47 v[x].push_back(y); 48 } 49 if(!flag) printf("No\n"); 50 else{ 51 memset(use, 0, sizeof(use)); 52 int sum = 0; 53 for(int i = 1; i <= n; ++i){ 54 memset(vis, false, sizeof(vis)); 55 if(FFind(i)) sum ++; 56 } 57 printf("%d\n", sum); 58 } 59 } 60 return 0; 61 }
染色判断二分图
1 #include <iostream> 2 #include <string.h> 3 #include <vector> 4 #include <queue> 5 using namespace std; 6 const int maxn = 205; 7 vector<int> v[maxn]; 8 int vis[maxn], num, num2, use[maxn]; 9 bool vi[maxn]; 10 bool Find(int x){ 11 for(int i = 0; i < v[x].size(); ++i){ 12 int xx = v[x][i]; 13 if(!vi[xx]){ 14 vi[xx] = true; 15 if(!use[xx] || Find(use[xx])){ 16 use[xx] = x; 17 return true; 18 } 19 } 20 } 21 return false; 22 } 23 bool dfs(int x){ 24 queue<int> q; 25 q.push(x); 26 vis[x] = 1; 27 while(!q.empty()){ 28 int y = q.front(); 29 q.pop(); 30 for(int i = 0; i < v[y].size(); ++i){ 31 int xx = v[y][i]; 32 if(vis[xx] == vis[y]) return false; 33 if(!vis[xx]){ 34 vis[xx] = vis[y] == 1 ? 2 : 1; 35 if(vis[xx] == 1) num ++; 36 else num2 ++; 37 q.push(xx); 38 } 39 } 40 } 41 return true; 42 } 43 int main(){ 44 int n, m; 45 while(~scanf("%d%d", &n, &m)){ 46 for(int i = 1; i <= n; ++i) v[i].clear(); 47 for(int i = 0; i < m; ++i){ 48 int x, y; 49 scanf("%d%d", &x, &y); 50 v[x].push_back(y), v[y].push_back(x); 51 } 52 if(m == 0){ 53 printf("0\n"); 54 continue; 55 } 56 bool flag = true; 57 memset(vis, 0, sizeof(vis)); 58 int ma = 0; 59 for(int i = 1; i <= n; ++i){ 60 if(!vis[i] && v[i].size() != 0){ 61 num = 1, num2 = 0; 62 if(!dfs(i)){ 63 flag = false; 64 break; 65 } 66 } 67 } 68 if(!flag) printf("No\n"); 69 else{ 70 memset(use, 0, sizeof(use)); 71 int sum = 0; 72 for(int i = 1; i <= n; ++i){ 73 memset(vi, false, sizeof(vi)); 74 if(Find(i)) sum ++; 75 } 76 printf("%d\n", sum/2); 77 } 78 } 79 return 0; 80 }
----------------------------------------------------------
http://acm.hdu.edu.cn/showproblem.php?pid=3478
染色
1 #include <iostream> 2 #include <queue> 3 #include <string.h> 4 #include <vector> 5 using namespace std; 6 const int maxn = 100009; 7 int vis[maxn], n, m, s; 8 vector<int> v[maxn]; 9 bool dfs(int x){ 10 memset(vis, 0, sizeof(vis)); 11 queue<int> q; 12 q.push(x); 13 vis[x] = 1; 14 int num = 1; 15 bool flag = false; 16 while(!q.empty()){ 17 int xx = q.front(); 18 //cout<<"%%%%%%%%%%%"<<xx<<endl; 19 q.pop(); 20 for(int i = 0; i < v[xx].size(); ++i){ 21 int xxx = v[xx][i]; 22 if(vis[xx] == vis[xxx]){ 23 //cout<<xx<<"****"<<xxx<<"***"<<vis[xx]<<endl; 24 flag = true; 25 } 26 if(!vis[xxx]){ 27 vis[xxx] = vis[xx] == 1 ? 2 : 1; 28 num++; 29 q.push(xxx); 30 } 31 } 32 } 33 //cout<<num<<"****"<<endl; 34 if(flag && num == n) return true; 35 else return false; 36 } 37 int main(){ 38 int t; 39 scanf("%d", &t); 40 for(int j = 1; j <= t; ++j){ 41 scanf("%d%d%d", &n, &m, &s); 42 for(int i = 0; i < n; ++i) v[i].clear(); 43 for(int i = 0; i < m; ++i){ 44 int x, y; 45 scanf("%d%d", &x, &y); 46 v[x].push_back(y), v[y].push_back(x); 47 } 48 if(dfs(s)){ 49 printf("Case %d: YES\n", j); 50 }else{ 51 printf("Case %d: NO\n", j); 52 } 53 } 54 return 0; 55 }
--------------------------------------------------
https://loj.ac/problem/526
从n个树中选择最大子集满足任意两个数x,y gcd(x,y)*gcd(x+1, y+1) != 1,易知同奇同偶一定满足,然后奇偶建边,求最大独立集,除去最大独立集就是所求
1 #include <iostream> 2 #include <vector> 3 #include <string.h> 4 using namespace std; 5 6 #define ll long long 7 ll a[555]; 8 vector<int> v[555]; 9 int use[555]; 10 bool vis[555]; 11 12 ll g(ll x, ll y){ 13 return y ? g(y, x%y) : x; 14 } 15 16 bool d(int x){ 17 for(int i = 0; i < v[x].size(); ++i){ 18 int xx = v[x][i]; 19 if(!vis[xx]){ 20 vis[xx] = true; 21 if(!use[xx] || d(use[xx])){ 22 use[xx] = x; 23 return true; 24 } 25 } 26 } 27 return false; 28 } 29 30 int main(){ 31 int n; 32 scanf("%d", &n); 33 for(int i = 1; i <= n; ++i){ 34 scanf("%lld", &a[i]); 35 } 36 for(int i = 1; i <= n; ++i) if(a[i]&1){ 37 for(int j = 1; j <= n; ++j) if(!(a[j]&1)){ 38 if(g(a[i], a[j]) == 1 && g(a[i]+1, a[j]+1) == 1) v[i].push_back(j); 39 } 40 } 41 int num = 0; 42 for(int i = 1; i <= n; ++i) if(a[i]&1){ 43 memset(vis, false, sizeof(vis)); 44 if(d(i)) num++; 45 } 46 printf("%d\n", n-num); 47 return 0; 48 }
--------------------------------------------------
只有不断学习才能进步!