很奇怪, 看到网上用的都是匈牙利算法求最大基数匹配

紫书上压根没讲这个算法, 而是用最大流求的。

难道是因为第一个人用匈牙利算法然后其他所有的博客都是看这个博客的吗?

很有可能……

回归正题。

题目中只差一个数字的时候可以匹配, 然后求最少模板数。

那么肯定匹配的越多就越少, 也就是求最多匹配多少。

这个时候我就想到了二分图最大基数匹配。

那么很容易想到可以匹配的一组之间就连一条弧。

但问题是怎么分成两类??分类的目的是让同一类之间没有弧, 这样才是二分图。

后来发现因为匹配的一组只有一个数字不一样, 所以肯定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 (最大流求二分图最大基数匹配)的更多相关文章

  1. 紫书 习题 11-9 UVa 12549 (二分图最小点覆盖)

    用到了二分图的一些性质, 最大匹配数=最小点覆盖 貌似在白书上有讲 还不是很懂, 自己看着别人的博客用网络流写了一遍 反正以后学白书应该会系统学二分图的,紫书上没讲深. 目前就这样吧. #includ ...

  2. 紫书 习题8-12 UVa 1153(贪心)

    本来以为这道题是考不相交区间, 结果还专门复习了一遍前面写的, 然后发现这道题的区间是不是 固定的, 是在一个范围内"滑动的", 只要右端点不超过截止时间就ok. 然后我就先考虑有 ...

  3. 紫书 习题8-7 UVa 11925(构造法, 不需逆向)

    这道题的意思紫书上是错误的-- 难怪一开始我非常奇怪为什么第二个样例输出的是2, 按照紫书上的意思应该是22 然后就不管了,先写, 然后就WA了. 然后看了https://blog.csdn.net/ ...

  4. 紫书 习题 11-10 UVa 12264 (二分答案+最大流)

    书上写的是UVa 12011, 实际上是 12264 参考了https://blog.csdn.net/xl2015190026/article/details/51902823 这道题就是求出一种最 ...

  5. 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, · · · ...

  6. 紫书 习题7-8 UVa 12107 (IDA*)

    参考了这哥们的博客 https://blog.csdn.net/hyqsblog/article/details/46980287  (1)atoi可以char数组转int, 头文件 cstdlib ...

  7. 紫书 习题 11-17 UVa 1670 (图论构造)

    一开始要符合题目条件, 那么肯定没有任何一个点是孤立的, 也就是说没有点的度数是1 所以我就想让度数是1的叶子节点相互连起来.然后WA 然后看这哥们的博客 https://blog.csdn.net/ ...

  8. 紫书 习题 8-21 UVa 1621 (问题分析方法)

    知道是构造法但是想了挺久没有什么思路. 然后去找博客竟然只有一篇!!https://blog.csdn.net/no_name233/article/details/51909300 然后博客里面又说 ...

  9. 紫书 习题8-18 UVa 11536 (扫描法)

    这道题貌似可以用滑动窗口或者单调栈做, 但是我都没有用到. 这道题要求连续子序列中和乘上最小值最大, 那么我们就可以求出每一个元素, 以它为最小值的的最大区间的值, 然后取max就ok了.那么怎么求呢 ...

随机推荐

  1. sklearn学习8-----GridSearchCV(自动调参)

    一.GridSearchCV介绍: 自动调参,适合小数据集.相当于写一堆循环,自己设定参数列表,一个一个试,找到最合适的参数.数据量大可以使用快速调优的方法-----坐标下降[贪心,拿当前对模型影响最 ...

  2. "啃下"插入排序

    插入排序法基本原理 插入排序法较冒泡排序法和选择排序法更贴近生活,应该来说理解起来更快.如果你现在能够得到一副麻将,请把里面的“一万”到“六万”拿出来,打乱顺序,再重新排好,就像打麻将开始那样.是否需 ...

  3. NOIP 2017 时间复杂度 (模拟)

    题目大意:略 傻了吧唧的我wa了好几次 我的模拟功底真的不咋地 linux下用gets会报错,我用的fgets #include <string> #include "stdio ...

  4. Python基本类型操作

    # str = "2017.1.1.wmv" # #print(str[str.rfind('.'):]) # #print(str.count(".")) # ...

  5. 【hdu 6321】Dynamic Graph Matching

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] DP 设f[i][j]表示前i个操作,已经匹配了的点的状态集合为j的方案数 对于+操作 有两种情况. 1.这条边作为匹配的边 2.这 ...

  6. 洛谷 P2298 Mzc和男家丁的游戏

    P2298 Mzc和男家丁的游戏 题目背景 mzc与djn的第二弹. 题目描述 mzc家很有钱(开玩笑),他家有n个男家丁(做过上一弹的都知道).他把她们召集在了一起,他们决定玩捉迷藏.现在mzc要来 ...

  7. [Ubuntu]安装中文输入法

    安装了英文版的Ubuntu12.04之后.使用ctrt+space无法切换到中文,才反应过来. 于是查询了下怎么在Ubuntu下安装和配置中文输入法. 第一步安装语言包: 在左側的菜单条中点击 sys ...

  8. 电脑显示U盘,可是读取不了

    问题: 我的一个内存卡没用,放到了读卡器上.刚開始能用,可是到了后来,突然之间发现: 插入读卡器之后,仅仅是在U下角显示有有U盘提示,提示"打开设备和打印"或者"安全删除 ...

  9. iOS UI01_UIView

    // //  AppDelegate.m //  UI01_UIView // //  Created by dllo on 15/7/29. //  Copyright (c) 2015年 zhoz ...

  10. Cordova 5 架构学习 Weinre远程调试技术

    手机上的页面不像桌面开发这么方便调试.能够使用Weinre进行远程调试以方便开发.本文介绍windows下的安装与使用. 安装 使用npm安装.能够执行: ###npm config set regi ...