二分图再次总结
二分圖首次總結
在caioj上刷了二分圖的題,比較有收獲
而且關鍵是網上找不到題解。
我開始幾道做不出,然后題解搜不到
其實這反而更有效果
很好的限制了我喜歡抄題解的習慣
只有自己去做,思維能力才能得到鍛煉
一定要克制自己抄題解!!!!!!!!
最大匹配1(二分圖)(元問題byscy):公牛母牛配
裸題。
注意邊加的時候是有向邊。
然后注意邊數可能很多,不要以為是樹,慣性思維
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std;const int MAXN = 1e4 + 10; const int MAXM = 1e5 + 10; struct Edge{ int to, next; } e[MAXM << 1]; int head[MAXN], tot; int vis[MAXN], link[MAXN], n, m, k;void AddEdge(int from, int to) {e[tot] = Edge{to, head[from]};head[from] = tot++; }bool dfs(int u) {for(int i = head[u]; ~i; i = e[i].next){int v = e[i].to;if(vis[v]) continue;vis[v] = 1;if(!link[v] || dfs(link[v])){link[v] = u;return true;}}return false; }int main() {memset(head, -1, sizeof(head)); tot = 0;scanf("%d%d%d", &n, &m, &k);_for(i, 1, k){int u, v;scanf("%d%d", &u, &v);AddEdge(u, v);}int ans = 0;_for(i, 1, n){memset(vis, 0, sizeof(vis));if(dfs(i)) ans++;}printf("%d\n", ans);return 0; }?
最大二分匹配2:上課(轉化模型)
可以抽象出一個模型
一個A點可以拓展出很多B點,只要選擇一個B點就可以覆蓋A點
一個B點只能覆蓋一個A點
求最多覆蓋多少A點
用二分圖最大匹配就好了
#include<bits/stdc++.h> #define ID(x, y) (x - 1) * 12 + y #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std;const int MAXN = 300 + 10; const int MAXM = 100; int n, a[MAXN][MAXN]; int link[MAXN], vis[MAXN];bool find(int u) {_for(v, 1, 84){if(!a[u][v] || vis[v]) continue;vis[v] = 1;if(!link[v] || find(link[v])){link[v] = u;return true;}}return false; }int main() {scanf("%d", &n);_for(i, 1, n){int t, p, q;scanf("%d", &t);while(t--){scanf("%d%d", &p, &q); a[i][ID(p, q)] = 1;}}int ans = 0;_for(i, 1, n){memset(vis, 0, sizeof(vis));if(find(i)) ans++;}printf("%d\n", ans);return 0; }?
最大二分匹配3:地鼠(轉化模型)
套用上一題的模型。能達到就連邊。
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std;const int MAXN = 100 + 10; int n, m, s, v; int a[MAXN][MAXN], vis[MAXN], link[MAXN]; double x[MAXN], y[MAXN];int find(int u) {_for(v, 1, m){if(!a[u][v] || vis[v]) continue;vis[v] = 1;if(!link[v] || find(link[v])){link[v] = u;return true;}}return false; }bool judge(int i, double xx, double yy) {return sqrt(pow(x[i] - xx, 2) + pow(y[i] - yy, 2)) <= (double)s * v; }int main() {while(~scanf("%d%d%d%d", &n, &m, &s, &v)){memset(a, 0, sizeof(a));memset(link, 0, sizeof(link));_for(i, 1, n) scanf("%lf%lf", &x[i], &y[i]);_for(i, 1, m){double xx, yy;scanf("%lf%lf", &xx, &yy);_for(j, 1, n) a[j][i] = judge(j, xx, yy);}int ans = 0;_for(i, 1, n){memset(vis, 0, sizeof(vis));if(find(i)) ans++;}printf("%d\n", n - ans);}return 0; }?
最小覆蓋1(二分圖)(元問題byscy)
最小覆蓋=最大匹配
代碼和最大匹配的一模一樣,不貼了
?
最小覆蓋2(模型轉換:地雷)
很經典的一道題
其實要理解透徹,抽象出一個模型
我的理解是,對于一個地雷,可以被這一行和這一列的炮擊毀。
所以把行看作X集合,列看作Y集合,地雷看作邊
這樣建圖后,一個點,也就是一行或者一列,就可以消滅這一行或這一列的地雷,
也就是說一個點可以消滅與其相連的邊
那么顯然最小覆蓋了
要理解本質
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std;const int MAXN = 500 + 10; const int MAXM = 1e4 + 10; struct Edge{ int to, next; } e[MAXM]; int head[MAXN], tot; int vis[MAXN], link[MAXN], n, m, k;void AddEdge(int from, int to) {e[tot] = Edge{to, head[from]};head[from] = tot++; }bool dfs(int u) {for(int i = head[u]; ~i; i = e[i].next){int v = e[i].to;if(vis[v]) continue;vis[v] = 1;if(!link[v] || dfs(link[v])){link[v] = u;return true;}}return false; }int main() {memset(head, -1, sizeof(head)); tot = 0;scanf("%d%d", &n, &m);_for(i, 1, m){int u, v;scanf("%d%d", &u, &v);AddEdge(u, v);}int ans = 0;_for(i, 1, n){memset(vis, 0, sizeof(vis));if(dfs(i)) ans++;}printf("%d\n", ans);return 0; }?
最小覆蓋2(模型轉換:草場淹水)
這題想了巨久。1.5h吧
其實這題可以用來檢驗你有沒有理解上一題的本質
在這道題
每個點可以被橫著的木板和豎著的木板消滅
那么類比上一題,就把橫著的木板和豎著的木板作為X集合和Y集合
這個點就作為邊,就ok了
注意要預處理出每一個木板的編號
不過我一開始覺得要超時。因為匈牙利算法是n三方的
然而這個編號可以到2500(大概這個數量級,實際上1000多左右,因為點和點可以合并)
但是交上去是0ms
可能是數據水,或者匈牙利算法實際上遠遠達不到n三方。
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std;const int MAXN = 50; const int MAXM = 2500; struct Edge{ int to, next; } e[MAXM * MAXM]; int head[MAXM], tot;int vis[MAXM], link[MAXM], n, m, id; int a1[MAXN][MAXN], a2[MAXN][MAXN]; char s[MAXN][MAXN];void AddEdge(int from, int to) {e[tot] = Edge{to, head[from]};head[from] = tot++; }bool dfs(int u) {for(int i = head[u]; ~i; i = e[i].next){int v = e[i].to;if(vis[v]) continue;vis[v] = 1;if(!link[v] || dfs(link[v])){link[v] = u;return true;}}return false; }int main() {memset(head, -1, sizeof(head)); tot = 0;scanf("%d%d", &n, &m);_for(i, 1, n) scanf("%s", s[i] + 1);id = 0;_for(j, 1, m)_for(i, 1, n)if(s[i][j] == '*'){int t = i; id++;while(s[t][j] == '*') a2[t++][j] = id;i = t - 1;}id = 0;_for(i, 1, n)_for(j, 1, m)if(s[i][j] == '*'){int t = j; id++;while(s[i][t] == '*') a1[i][t++] = id;j = t - 1;}_for(i, 1, n)_for(j, 1, m)if(s[i][j] == '*')AddEdge(a1[i][j], a2[i][j]);int ans = 0;_for(i, 1, id){memset(vis, 0, sizeof(vis));if(dfs(i)) ans++;}printf("%d\n", ans);return 0; }?
最后剩下一道題,一般圖的最大獨立子集。
不會……
轉載于:https://www.cnblogs.com/sugewud/p/9930370.html
總結
- 上一篇: SpringMVC重定向传参
- 下一篇: 如何创建高质量的TypeScript声明