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的更多相关文章

  1. [WC2016]挑战NPC(一般图最大匹配)

    [WC2016]挑战NPC(一般图最大匹配) Luogu 题解时间 思路十分有趣. 考虑一个筐只有不多于一个球才有1的贡献代表什么. 很明显等效于有至少两个位置没有被匹配时有1的贡献. 进而可以构造如 ...

  2. [BZOJ]4405: [wc2016]挑战NPC(带花树)

    带花树模板 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; ...

  3. [bzoj4405][wc2016]挑战NPC

    来自FallDream的博客,未经允许,请勿转载,谢谢. 小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目: 有n个球,用整数1到n编号.还有m个筐子,用整数1到m编号. ...

  4. BZOJ 4405 [wc2016]挑战NPC 带花树 一般图最大匹配

    https://www.lydsy.com/JudgeOnline/problem.php?id=4405 这道题大概就是考场上想不出来,想出来也调不出来的题. 把每个桶拆成三个互相有边的点,每个球向 ...

  5. [UOJ171][WC2016]挑战NPC

    uoj luogu bzoj sol 你可以列一个表格. 一个框子里放球的数量 0 1 2 3 对"半空框子"数量的贡献 1 1 0 0 把一个框子拆三个点.两两之间连边. 会发现 ...

  6. bzoj 4405: [wc2016]挑战NPC【带花树】

    把每个筐子拆成3个,分别表示放0/1/2个,然后把这三个点两两连起来,每一个可以放在筐里的球都想这三个点连边. 这样可以发现,放0个球的时候,匹配数为1,放1个球的时候,匹配数为1,放2个球的时候,匹 ...

  7. 「WC2016」挑战NPC

    「WC2016」挑战NPC 解题思路 这个题建图非常厉害,带花树什么的只会口胡根本写不动,所以我写了机房某大佬教我的乱搞. 考虑把一个筐 \(x\) 拆成 \(x1,x2,x3\) 三个点,且这三个点 ...

  8. 【BZOJ4405】【WC2016】挑战NPC(带花树)

    [BZOJ4405][WC2016]挑战NPC(带花树) 题面 BZOJ 洛谷 Uoj Description 小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目: 有n个 ...

  9. UOJ171 【WC2016】挑战NPC

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

随机推荐

  1. 【算法】C++用链表实现一个箱子排序附源代码详解

    01 箱子排序 1.1 什么是分配排序? 分配排序的基本思想:排序过程无须比较关键字,而是通过"分配"和"收集"过程来实现排序.它们的时间复杂度可达到线性阶:O ...

  2. P3952 时间复杂度

    P3952 时间复杂度 题目描述 小明正在学习一种新的编程语言 A++,刚学会循环语句的他激动地写了好多程序并 给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序, 于是你的机 ...

  3. NOIP模拟题汇总(加厚版)

    \(NOIP\)模拟题汇总(加厚版) T1 string 描述 有一个仅由 '0' 和 '1' 组成的字符串 \(A\),可以对其执行下列两个操作: 删除 \(A\)中的第一个字符: 若 \(A\)中 ...

  4. 欧拉筛(线性筛) & 洛谷 P3383 【模板】线性筛素数

    嗯.... 埃氏筛和欧拉筛的思想都是相似的: 如果一个数是素数,那么它的所有倍数都不是素数.... 这里主要介绍一下欧拉筛的思路:(欧拉筛的复杂度大约在O(n)左右... 定义一个prime数组,这个 ...

  5. python全栈开发学习_day2_语言种类及变量

    一.编程语言的分类及python相对其他语言的优势 1)三大语言种类及细分 1.机器语言(低级语言):直接用计算能够理解的二进制进行编写,直接控制计算机硬件. 优点:执行效率高. 缺点:开发效率低,跨 ...

  6. [八分之三的男人] POJ - 1741 点分治 && 点分治笔记

    题意:给出一棵带边权树,询问有多少点对的距离小于等于\(k\) 本题解参考lyd的算法竞赛进阶指南,讲解的十分清晰,比网上那些讲的乱七八糟的好多了 不过写起来还是困难重重(史诗巨作 打完多校更详细做法 ...

  7. Tomcat中查看JVM内存使用情况

    TOMCAT运行时,实时监控当前应用JVM的使用情况:可以利用Tomcat自带的应用manager查看详情. 首先,确认服务目录webapps下有manager应用 其次,需要创建角色manager和 ...

  8. Java_方法的基本语法格式

    [修饰符] 返回值类型 方法名称([参数列表]){ 方法体 } [ ]中的内容是可有可无的 暂时将方法的修饰符编写为 public static 返回值类型有两种情况 : 第一种:无返回值类型,也就是 ...

  9. html5实现判断拍照旋转角度等功能

    https://www.aliyun.com/jiaocheng/857189.html     base64图片编码上传,判断图片是否有旋转,若有旋转修正图片并保存至阿里 http://code.c ...

  10. python学习-基础知识-1

    1.计算机历史 计算机使用高低电压的两种状态来描述信息.计算机可以理解的只有二进制数据即010100011....,1个比特位可以表示的状态只有2种,n个比特位可以表示的状态有2的n次方种. 所以如果 ...