首页 > 代码库 > 二分图类题目集合
二分图类题目集合
此文用来总结二分图相关知识的题目,以后遇到了就囤在一起总结吧。
最近遇到的一道最小路径覆盖的题目,其实很裸,忘了也没看出来就是最小路径覆盖。
第四届“恒生杯”程序设计大赛决赛 A
http://acm.hust.edu.cn/problem/show/1643
题意:有n个物品,每一天只能选取一些满足条件的物品,即选取的物品相邻之间要满足abs(a[i]-a[j]) >= k,问最少多少天能够选完所有物品。
分析:首先建立一个图,对于abs(a[i]-a[j])>=k的i,j(i < j)建一条i->j又向边,然后就是直接最小路径覆盖了。
每个点拆成2点i,i‘,分别表示起点和终点,对于i->j的边,拆点后连i->j‘的边,总点数n-二分图最大匹配数就是答案。
可以简单证明一下,二分图每一次匹配一条边,相当于在原图中走一步,那么我们的目标是一直走下去,走最少次数将所有的点访问完,而且每个点只能走一次。
原图对每个点走一次,最多走n次便可,现在匹配一条边后需要n-1次,这样最大匹配k条边,说明原图最少需要n-k次。最大匹配中每个点最多与一条匹配边相关联实际上就能表示,每个点只能访问一次。
代码:
1 #include <bits/stdc++.h> 2 #define in freopen("data.txt", "r", stdin); 3 #define bug(x) printf("Line %d:>>>>>>>>>>\n", (x)); 4 5 using namespace std; 6 const int maxn = 333; 7 int vis[maxn], link[maxn], g[maxn][maxn]; 8 int a[maxn], n; 9 bool dfs(int x) {10 for(int y = 1; y <= n; y++) if(g[x][y]) {11 if(vis[y]) continue;12 vis[y] = 1;13 if(link[y] == 0 || dfs(link[y])) {14 link[y] = x;15 return true;16 }17 }18 return false;19 }20 int main() {21 22 int T, k;23 for(int t = scanf("%d", &T); t <= T; t++) {24 scanf("%d%d", &n, &k);25 memset(link, 0, sizeof link);26 memset(g, 0, sizeof g);27 for(int i = 1; i <= n; i++)28 scanf("%d", a+i);29 for(int i = 1; i <= n; i++)30 for(int j = i+1; j <= n; j++)31 if(abs(a[i]-a[j]) >= k) g[i][j] = 1;32 int ans = 0;33 for(int i = 1; i <= n; i++) {34 memset(vis, 0, sizeof vis);35 if(dfs(i))36 ans++;37 }38 cout << n-ans << endl;39 }40 return 0;41 }
二分图类题目集合
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。