紫书 习题 11-8 UVa 1663 (最大流求二分图最大基数匹配)
很奇怪, 看到网上用的都是匈牙利算法求最大基数匹配
紫书上压根没讲这个算法, 而是用最大流求的。
难道是因为第一个人用匈牙利算法然后其他所有的博客都是看这个博客的吗?
很有可能……
回归正题。
题目中只差一个数字的时候可以匹配, 然后求最少模板数。
那么肯定匹配的越多就越少, 也就是求最多匹配多少。
这个时候我就想到了二分图最大基数匹配。
那么很容易想到可以匹配的一组之间就连一条弧。
但问题是怎么分成两类??分类的目的是让同一类之间没有弧, 这样才是二分图。
后来发现因为匹配的一组只有一个数字不一样, 所以肯定1的个数不同(或者0)
那么我们就可以根据1的个数的奇偶分两类, 这样才能构造出二分图。
然后我就这么交了, 然后WA。
后来发现貌似模板可能会重复, 因为是集合, 满足互异性, 所以这些重复的肯定是要去掉的。
这是个大坑……
所以加模板的时候要判断有没有加过。
然后最大流求最大基数匹配就ok了!
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
#include<iostream>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;
const int MAXN = 2123;
struct Edge { int from, to, cap, flow; };
vector<Edge> edges;
vector<int> g[MAXN];
vector<string> num;
int cur[MAXN], h[MAXN], s, t, n, m;
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge{from, to, cap, 0});
edges.push_back(Edge{to, from, 0, 0});
g[from].push_back(edges.size() - 2);
g[to].push_back(edges.size() - 1);
}
bool bfs()
{
queue<int> q;
memset(h, 0, sizeof(h));
q.push(s);
h[s] = 1;
while(!q.empty())
{
int x = q.front(); q.pop();
REP(i, 0, g[x].size())
{
Edge& e = edges[g[x][i]];
if(e.cap > e.flow && !h[e.to])
{
h[e.to] = h[x] + 1;
q.push(e.to);
}
}
}
return h[t];
}
int dfs(int x, int a)
{
if(x == t || a == 0) return a;
int flow = 0, f;
for(int& i = cur[x]; i < g[x].size(); i++)
{
Edge& e = edges[g[x][i]];
if(h[x] + 1 == h[e.to] && (f = dfs(e.to, min(e.cap - e.flow, a))) > 0)
{
e.flow += f;
edges[g[x][i] ^ 1].flow -= f;
flow += f;
if((a -= f) == 0) break;
}
}
return flow;
}
int maxflow()
{
int flow = 0;
while(bfs()) memset(cur, 0, sizeof(cur)), flow += dfs(s, 1e9);
return flow;
} //从这以上都是求最大流
int sum(string s) //模板中1的个数
{
int ret = 0;
REP(i, 0, s.length()) ret += (s[i] == '1');
return ret & 1;
}
bool judge(string s) //记住集合中不能有重复元素
{
REP(i, 0, num.size())
if(s == num[i])
return false;
return true;
}
int main()
{
while(~scanf("%d%d", &n, &m) && n && m)
{
num.clear();
REP(i, 0, MAXN) g[i].clear();
edges.clear();
while(m--)
{
string s;
cin >> s;
if(s.find('*') == -1) { if(judge(s)) num.push_back(s); }
else
{
int p; for(p = 0; s[p] != '*'; p++); //拆成两个模板
s[p] = '0'; if(judge(s)) num.push_back(s);
s[p] = '1'; if(judge(s)) num.push_back(s);
}
}
s = num.size(); t = s + 1; //源点和汇点
REP(i, 0, num.size())
{
if(sum(num[i])) AddEdge(s, i, 1); //如果这个点是奇的, 那么从源点到奇数点连一条弧
else AddEdge(i, t, 1); // 偶的则从这个点到汇点连一条弧
REP(j, i + 1, num.size())
{
int cnt = 0;
REP(k, 0, n)
{
if(num[i][k] != num[j][k]) cnt++;
if(cnt > 1) break;
}
if(cnt == 1)
{
if(sum(num[i])) AddEdge(i, j, 1); //注意这里奇数点在左侧, 偶数点在右侧, 弧的方向不能错
else AddEdge(j, i, 1);
}
}
}
printf("%d\n", num.size() - maxflow()); //总的模板数减去匹配数即是答案
}
return 0;
}
紫书 习题 11-8 UVa 1663 (最大流求二分图最大基数匹配)的更多相关文章
- 紫书 习题 11-9 UVa 12549 (二分图最小点覆盖)
用到了二分图的一些性质, 最大匹配数=最小点覆盖 貌似在白书上有讲 还不是很懂, 自己看着别人的博客用网络流写了一遍 反正以后学白书应该会系统学二分图的,紫书上没讲深. 目前就这样吧. #includ ...
- 紫书 习题8-12 UVa 1153(贪心)
本来以为这道题是考不相交区间, 结果还专门复习了一遍前面写的, 然后发现这道题的区间是不是 固定的, 是在一个范围内"滑动的", 只要右端点不超过截止时间就ok. 然后我就先考虑有 ...
- 紫书 习题8-7 UVa 11925(构造法, 不需逆向)
这道题的意思紫书上是错误的-- 难怪一开始我非常奇怪为什么第二个样例输出的是2, 按照紫书上的意思应该是22 然后就不管了,先写, 然后就WA了. 然后看了https://blog.csdn.net/ ...
- 紫书 习题 11-10 UVa 12264 (二分答案+最大流)
书上写的是UVa 12011, 实际上是 12264 参考了https://blog.csdn.net/xl2015190026/article/details/51902823 这道题就是求出一种最 ...
- UVA 1594 Ducci Sequence(紫书习题5-2 简单模拟题)
A Ducci sequence is a sequence of n-tuples of integers. Given an n-tuple of integers (a1, a2, · · · ...
- 紫书 习题7-8 UVa 12107 (IDA*)
参考了这哥们的博客 https://blog.csdn.net/hyqsblog/article/details/46980287 (1)atoi可以char数组转int, 头文件 cstdlib ...
- 紫书 习题 11-17 UVa 1670 (图论构造)
一开始要符合题目条件, 那么肯定没有任何一个点是孤立的, 也就是说没有点的度数是1 所以我就想让度数是1的叶子节点相互连起来.然后WA 然后看这哥们的博客 https://blog.csdn.net/ ...
- 紫书 习题 8-21 UVa 1621 (问题分析方法)
知道是构造法但是想了挺久没有什么思路. 然后去找博客竟然只有一篇!!https://blog.csdn.net/no_name233/article/details/51909300 然后博客里面又说 ...
- 紫书 习题8-18 UVa 11536 (扫描法)
这道题貌似可以用滑动窗口或者单调栈做, 但是我都没有用到. 这道题要求连续子序列中和乘上最小值最大, 那么我们就可以求出每一个元素, 以它为最小值的的最大区间的值, 然后取max就ok了.那么怎么求呢 ...
随机推荐
- Cookie和Session有什么区别
1. 由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识别具体的用户,这个机制就是Session. 典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状 ...
- python位操作(进制)与ascii
位操作符 位操作的操作符与python的set的操作符一样.与C语言中的位操作符也是一样的. a = 60 #60的二进制为 0011 1100b = 13 #13的二进制为 00001101 c = ...
- 代理上网环境配置docker私有库
最后更新时间:2018年12月27日 Docker使用代理上网去 pull 各类 images,需要做如下配置: 创建目录: /etc/systemd/system/docker.service.d ...
- 2.安装Cython
许多科学的Python发行版,例如Anaconda,Enthought Canopy和Sage,捆绑Cython并且不需要设置. 与大多数Python软件不同,Cython需要在系统上存在C编译器.获 ...
- VUE:条件渲染和列表渲染
条件渲染 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <titl ...
- Virtual Box 新建一个虚拟机安装系统(补充:WIN7 64 bit 系统虚拟机无法安装 64 bit 系统问题)
1.安装Virtual Box好后,点击新建 2.配置内存大小,这个根据自己需要配置就好 3.创建虚拟硬盘 这里选择固定分配.动态分配都可以,接下来就分配硬盘大小了 4.新建好后我们点击刚才建立的虚拟 ...
- web.xml中Filter过滤器标签说明
原文:http://www.cnblogs.com/edwardlauxh/archive/2010/03/11/1918618.html 在研究liferay框架中看到Web.xml中加入了过滤器的 ...
- WinServer-服务器管理器-从入门到放弃
WIN7 远程服务器管理工具 看看这篇帖子,他们说可以在WIN7上通过服务器管理工具来管理服务器上的软件 https://social.technet.microsoft.com/Forums/zh- ...
- Picking up Jewels
Picking up Jewels There is a maze that has one entrance and one exit. Jewels are placed in passages ...
- ORA 12505 Listener does not currently know of SID given in connection descriptor
oracle数据库正常启动后.在本地能够正常訪问,可是远程使用sqldevelop却不能訪问.提示ORA 12505 Listener does not currently know of SID g ...