紫书 习题 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了.那么怎么求呢 ...
随机推荐
- Git的初始化设置
Git安装成功之后,新建一个初始化的仓库以及配置GitHub仓库 Git配置GitHub账户 安装完成之后要进行git的配置,这里配置的是GitHub账户 MisSa@DESKTOP-PIQ06QO ...
- Node_进阶_1
第一天 1.1简介 Node.js简介 V8引擎本身就是用于Chrome浏览器的JS解释部分,Ryan Dahl把这个V8搬到了服务器上,用于做服务器的软件. Node.js是一个让Javascrip ...
- 给iview组件select设置默认值
1.首先,给select加一个v-model,如: <Select v-model="exam_name" > <Option v-for="(item ...
- php字符处理
1.strstr 截取某个字符后的字符: echo strstr("123456789","5");//输出:6789
- ECharts树图节点过多时取消缩放,调整容器高度自适应内容变化
问题现象 使用ECharts树图,在数据维度大,节点过多时,所看到的内容会重叠交错,无法查看. 原因 在给定ECharts树图容器尺寸后,无论数据多么庞大或者稀少,数据始终会尝试在给定容器内撑满.全部 ...
- 2019-03-28 SQL Server Table
-- table 是实际表 view是虚表.你可以认为view是一个查询的结果 -- 声明@tbBonds table declare @tbBonds table(TrustBondId int n ...
- n&(n-1)位运算的妙用
一.n-1发生了什么 ①.二进制数n,n-1后,如果最后一位是0,将向前一位借2,2-1=1.最后一位为1.如果前一位为0,将继续向前一位借2,加上本身少掉的1.则变为1.一直遇到1.减为0. 所以 ...
- vue-router的创建(1)
vue-router的创建 <!doctype html> <html lang="en"> <head> <meta charset=& ...
- 洛谷 P3576 [POI2014]MRO-Ant colony
P3576 [POI2014]MRO-Ant colony 题目描述 The ants are scavenging an abandoned ant hill in search of food. ...
- uva725_一道水题(优化到了29ms)
//////////////////////////////////////////////////////////////////////////////////////////////////// ...