紫书 习题 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了.那么怎么求呢 ...
随机推荐
- HDU 5289 Assignment [优先队列 贪心]
HDU 5289 - Assignment http://acm.hdu.edu.cn/showproblem.php?pid=5289 Tom owns a company and he is th ...
- HDU 4630 No Pain No Game (线段树+离线)
题目大意:给你一个无序的1~n的排列a,每次询问[l,r]之间任取两个数得到的最大gcd是多少 先对所有询问离线,然后把问题挂在区间的左端点上(右端点也行) 在预处理完质数,再处理一个next数组,表 ...
- tensorflow之tf.slice()
转载:https://www.jianshu.com/p/71e6ef6c121b https://www.cnblogs.com/chamie/p/11073363.html def slice(i ...
- 自备LocalDateTime工具类
package cn.zytao.taosir.common.utils; import java.time.Instant; import java.time.LocalDate; import j ...
- C# .net IDE Rider入门
话说史上最强IDE Visual Studio 所向披靡数十载尚无敌手,现在Intellij带着统一IDE界的目标来挑战VS的霸主地位.了解Rider后发现,哎哟亮点多多,还不错哦! Rider是一款 ...
- 【codeforces 505D】Mr. Kitayuta's Technology
[题目链接]:http://codeforces.com/problemset/problem/505/D [题意] 让你构造一张有向图; n个点; 以及所要求的m对联通关系(xi,yi) 即要求这张 ...
- ASP.NET-ActionFilter过滤器用法实例
ActionFilter可以对每一个传过来的action请求进行过滤,非常有用,但是如果在这里判断过多,那么网站的性能和速度会不会变慢,这个问题值得思考,现在先放在这里. public class A ...
- angular-输入验证
$dirty 表单有填写记录 $valid 字段内容合法的 $invalid 字段内容是非法的 $pristine 表单没有填写记录 客户端的验证不能确保用户输入数据的安全,所以服务端的数据验证也是必 ...
- 关于nodejs的线程模型可以看这篇文章
虽然还是有一些没有讲全,但是整体还是讲的很不错的. http://www.ruanyifeng.com/blog/2014/10/event-loop.html
- Java String内存释放
Java String内存释放 这是一个坑,Java对于String对象,不进行内存的回收: 处理大数据量的时候,少用String. 与JDK有关系:jdk1.6环境下,内存只占用10M,jdk1.8 ...