[WC2016]挑战NPC
Sol
这做法我是想不到\(TAT\)
每个筐子拆成三个相互连边
球向三个筐子连边
然后跑一般图最大匹配
这三个筐子间最多有一个匹配
那么显然每个球一定会放在一个筐子里,一定有一个匹配
如果筐子间有匹配,则有一个半空的筐子,因为它一定只匹配了小于等于\(1\)个球
答案为匹配数\(-n\)
使答案最大即匹配数最大
上带花树就好了
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(1005);
const int __(2e5 + 5);
typedef int Arr[_];
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
Arr first, match, fa, vis, tim, pre;
int n, m, cnt, idx, ans, E, t1, t2, t3;
queue <int> Q;
struct Edge{
int to, next;
} edge[__];
IL void Add(RG int u, RG int v){
edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++;
edge[cnt] = (Edge){u, first[v]}, first[v] = cnt++;
}
IL int Find(RG int x){
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
IL int LCA(RG int x, RG int y){
++idx, x = Find(x), y = Find(y);
while(tim[x] != idx){
tim[x] = idx;
x = Find(pre[match[x]]);
if(y) swap(x, y);
}
return x;
}
IL void Blossom(RG int x, RG int y, RG int p){
while(Find(x) != p){
pre[x] = y, y = match[x];
if(vis[y] == 2) vis[y] = 1, Q.push(y);
if(Find(x) == x) fa[x] = p;
if(Find(y) == y) fa[y] = p;
x = pre[y];
}
}
IL int Aug(RG int S){
for(RG int i = 1; i <= t3; ++i) vis[i] = pre[i] = 0, fa[i] = i;
while(!Q.empty()) Q.pop();
Q.push(S), vis[S] = 1;
while(!Q.empty()){
RG int u = Q.front(); Q.pop();
for(RG int e = first[u]; e != -1; e = edge[e].next){
RG int v = edge[e].to;
if(Find(v) == Find(u) || vis[v] == 2) continue;
if(!vis[v]){
vis[v] = 2, pre[v] = u;
if(!match[v]){
for(RG int x = v, lst; x; x = lst)
lst = match[pre[x]], match[pre[x]] = x, match[x] = pre[x];
return 1;
}
vis[match[v]] = 1, Q.push(match[v]);
}
else{
RG int p = LCA(u, v);
Blossom(u, v, p);
Blossom(v, u, p);
}
}
}
return 0;
}
int main(RG int argc, RG char *argv[]){
for(RG int T = Input(); T; --T){
n = Input(), m = Input(), E = Input();
t1 = n + m, t2 = t1 + m, t3 = t2 + m;
ans = cnt = idx = 0;
for(RG int i = 1; i <= t3; ++i) first[i] = -1, match[i] = 0, tim[i] = 0;
for(RG int i = 1; i <= m; ++i)
Add(n + i, t1 + i), Add(t1 + i, t2 + i), Add(n + i, t2 + i);
for(RG int i = 1, u, v; i <= E; ++i){
u = Input(), v = Input();
Add(u, n + v), Add(u, t1 + v), Add(u, t2 + v);
}
for(RG int i = 1; i <= t3; ++i) if(!match[i]) ans += Aug(i);
printf("%d\n", ans - n);
}
return 0;
}
[WC2016]挑战NPC的更多相关文章
- [WC2016]挑战NPC(一般图最大匹配)
[WC2016]挑战NPC(一般图最大匹配) Luogu 题解时间 思路十分有趣. 考虑一个筐只有不多于一个球才有1的贡献代表什么. 很明显等效于有至少两个位置没有被匹配时有1的贡献. 进而可以构造如 ...
- [BZOJ]4405: [wc2016]挑战NPC(带花树)
带花树模板 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; ...
- [bzoj4405][wc2016]挑战NPC
来自FallDream的博客,未经允许,请勿转载,谢谢. 小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目: 有n个球,用整数1到n编号.还有m个筐子,用整数1到m编号. ...
- BZOJ 4405 [wc2016]挑战NPC 带花树 一般图最大匹配
https://www.lydsy.com/JudgeOnline/problem.php?id=4405 这道题大概就是考场上想不出来,想出来也调不出来的题. 把每个桶拆成三个互相有边的点,每个球向 ...
- [UOJ171][WC2016]挑战NPC
uoj luogu bzoj sol 你可以列一个表格. 一个框子里放球的数量 0 1 2 3 对"半空框子"数量的贡献 1 1 0 0 把一个框子拆三个点.两两之间连边. 会发现 ...
- bzoj 4405: [wc2016]挑战NPC【带花树】
把每个筐子拆成3个,分别表示放0/1/2个,然后把这三个点两两连起来,每一个可以放在筐里的球都想这三个点连边. 这样可以发现,放0个球的时候,匹配数为1,放1个球的时候,匹配数为1,放2个球的时候,匹 ...
- 「WC2016」挑战NPC
「WC2016」挑战NPC 解题思路 这个题建图非常厉害,带花树什么的只会口胡根本写不动,所以我写了机房某大佬教我的乱搞. 考虑把一个筐 \(x\) 拆成 \(x1,x2,x3\) 三个点,且这三个点 ...
- 【BZOJ4405】【WC2016】挑战NPC(带花树)
[BZOJ4405][WC2016]挑战NPC(带花树) 题面 BZOJ 洛谷 Uoj Description 小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目: 有n个 ...
- UOJ171 【WC2016】挑战NPC
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
随机推荐
- 10分钟教你用Python实现微信自动回复
01 前言&&效果展示 相信大家都有忙碌的时候,不可能一直守在微信上及时回复消息.但微信又不能像QQ一样设置自动回复.无妨,今天,我们就来用Python实现微信的自动回复功能吧,并且把 ...
- 通过cookie绕过验证码登录
在我们做自动化的时候碰到一些比较难破解的验证码时是非常头疼的,一般来说最好的办法就是让开发屏蔽,这样最有益身心健康. 那么今天我介绍的这个方法也挺简单的,就是通过添加cookie的方式绕过验证码直接登 ...
- todocmvc的安装
安装依赖 官网 安装依赖的css,js $npm install 引入vue <script src="js/vue.js"></script> 定义初始化 ...
- centos的基本命令01
01:创建用户命令 useradd liulaoshi # 创建用户 passwd liulaoshi # 设置密码, 回车后会提示让你输入两次密码 1.用户列表文件:/etc/passwd/ 2.用 ...
- leetcode 4 - binary search
注意: 1)需要保证nums1 的长度比 nums2 的长度小:(否则vector指针会越界) 2) 当分割线(partition)在首或尾时,用INT_MIN 和 INT_MAX 代替. 思路: ...
- python函数参数类型及其顺序
根据inspect模块官文文档中关于函数参数类型的相关说明,python函数参数共有五种类型,按顺序分别为:POSITIONAL_ONLY.POSITIONAL_OR_KEYWORD.VAR_POSI ...
- CentOS&.NET Core初试系列
目的 对前段时间学习.NET Core的知识进行一次入门篇的总结,希望加深印象同时帮助刚学同学少走一些坑. 目录 CentOS的安装和网卡的配置 安装.NET Core SDK和发布网站 Nginx的 ...
- 未来一年的13大手机APP开发趋势
无论是欢呼出租车,保存票据,订购披萨还是在线购物,您可以立即联系到什么设备?你的智能手机 这是您需要的朋友,在如何查找信息和简化日常任务方面发挥着不可或缺的作用. 移动技术以光速增长; 我们不能否认手 ...
- VS2010,VS2012,VS2015等的自动提示不能默认选中的功能解决办法
很简单,只需要按 ctrl+alt+space 即可切换. 蛋疼,我到底为什么总会不小心切换过去,而且每次都记不住这个快捷键切换回来...
- android 用命令行打包生成 apk
android 用 ant 进行 build. android sdk 下面的 tools/ant 下面的 build.xml 就是 build 的整个过程. 其中的 build 参数可在 ant.p ...