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 }

 

 

 

--------------------------------------------------

 

 

只有不断学习才能进步!

 

posted @ 2018-04-14 13:55  wenbao  阅读(212)  评论(0编辑  收藏  举报