日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

二分图再次总结

發布時間:2025/3/8 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 二分图再次总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

二分圖首次總結

在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

總結

以上是生活随笔為你收集整理的二分图再次总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。