http://uoj.ac/problem/171

带花树开花时的u和v一定要记清楚顺序,想好了再写,数据范围也要算好!

对每个筐子拆成3个点,连成一个三元环,对每个(u,v),让u和v的3个点都连边,这样跑一般图最大匹配(先增广每个球),可以发现所有的球都能放到一个筐子里,而且半空的筐子代表的三元环一定有一条边有匹配。

匹配总数=n+半空的筐子数,最大化匹配总数也相当于最大化半空的筐子数。

还可以发现三元环没必要连三条边,任选两个点连一条边也是一样的。

时间复杂度\(O(n^3)\)。

abclzr:“好神的建图啊,我一辈子也想不出来。”

reflash:“没关系,下辈子继续想。”

abclzr:“……”

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int N = 603;
const int M = 100003; struct node {int nxt, to;} E[M << 1];
int cnt, point[N], n, m, e, s[N], qu[N]; void ins(int u, int v) {E[++cnt] = (node) {point[u], v}; point[u] = cnt;} int tt[N], id[N], tot, fa[N], pre[N], Next[N]; int find(int x) {return fa[x] == x ? x : (fa[x] = find(fa[x]));} int p, q, tim = 0, vis[N];
int findlca(int u, int v) {
++tim;
while (true) {
if (u) {
if (vis[u] == tim)
return u;
vis[u] = tim;
u = find(pre[Next[u]]);
}
swap(u, v);
}
} void blossom(int u, int v, int lca) {
while (find(u) != lca) {
pre[u] = v;
v = Next[u];
if (s[v] == 1) {s[v] = 0; if (++q == N) q = 0; qu[q] = v;}
if (fa[u] == u) fa[u] = lca;
if (fa[v] == v) fa[v] = lca;
u = pre[v];
}
} int match(int x) {
memset(s, -1, sizeof(int) * (tot + 1));
for (int i = 1; i <= tot; ++i) fa[i] = i;
p = 0; q = 1; s[qu[1] = x] = 0; pre[x] = 0; int u, v;
while (p != q) {
if (++p == N) p = 0; u = qu[p];
for (int i = point[u]; i; i = E[i].nxt) {
v = E[i].to;
if (s[v] == -1) {
s[v] = 1; pre[v] = u;
if (!Next[v]) {
int last;
while (u) {
last = Next[u];
Next[u] = v; Next[v] = u;
u = pre[v = last];
}
return 1;
}
s[Next[v]] = 0; if (++q == N) q = 0; qu[q] = Next[v];
} else if (s[v] == 0 && find(u) != find(v)) {
int lca = findlca(fa[u], fa[v]);
blossom(u, v, lca);
blossom(v, u, lca);
}
}
} return 0;
} int main() {
int T; scanf("%d", &T);
while (T--) {
scanf("%d%d%d", &n, &m, &e);
tt[0] = n - 2;
for (int i = 1; i <= m; ++i) {
tt[i] = tt[i - 1] + 3;
id[tt[i]] = id[tt[i] + 1] = id[tt[i] + 2] = i;
} int u, v; tot = tt[m] + 2;
cnt = 0;
memset(point, 0, sizeof(int) * (tot + 1));
memset(Next, 0, sizeof(int) * (tot + 1)); for (int i = 1; i <= e; ++i) {
scanf("%d%d", &u, &v);
ins(u, tt[v]); ins(tt[v], u);
ins(u, tt[v] + 1); ins(tt[v] + 1, u);
ins(u, tt[v] + 2); ins(tt[v] + 2, u);
}
for (int i = 1; i <= m; ++i) ins(tt[i], tt[i] + 1), ins(tt[i] + 1, tt[i]); int ans = 0;
for (int i = 1; i <= tot; ++i)
if (!Next[i])
ans += match(i); printf("%d\n", ans - n);
for (int i = 1; i <= n; ++i)
printf("%d ", id[Next[i]]);
puts("");
} return 0;
}

【UOJ #171】【WC 2016】挑战NPC的更多相关文章

  1. 「WC2016」挑战NPC

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

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

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

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

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

  4. UOJ 171 【WC2016】挑战NPC

    一开始还真没想到是一般图匹配这种模型(毕竟才会的带花树) 把每一个盒子拆成3个,每一个可以放置进它的小球分别向这三个点连边,然后这三个点在连成一个三元环,最终答案就是小球数目-匹配数. 由于是一般图, ...

  5. 【刷题】UOJ #171 【WC2016】挑战NPC

    小 N 最近在研究 NP 完全问题,小 O 看小 N 研究得热火朝天,便给他出了一道这样的题目: 有 \(n\) 个球,用整数 \(1\) 到 \(n\) 编号.还有 \(m\) 个筐子,用整数 \( ...

  6. [UOJ171][WC2016]挑战NPC

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

  7. UOJ171 【WC2016】挑战NPC

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

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

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

  9. [bzoj4405][wc2016]挑战NPC

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

随机推荐

  1. Problem E. Matrix from Arrays(杭电2018年多校第四场+思维+打表找循环节)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6336 题目: 题意:给你一个l个元素的数组a,用题目中的程序构造一个新的矩阵,询问q次,问以(x1,y ...

  2. Centos7的iso everything与DVD以及Live的区别

    DVD.ISO 可以用安装程序安装的所有安装包,推荐镜像 Netinstall.iso 从网络安装或者救援系统 Everything.iso 包含centos7的一套完整的软件包,可以用来安装系统或者 ...

  3. 有向有权图的最短路径算法--Dijkstra算法

    Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Di ...

  4. Vim中的键映射【转】

    转自:http://www.cnblogs.com/softwaretesting/archive/2011/09/28/2194515.html http://www.pythonclub.org/ ...

  5. 005 JAVA多线程和并发基础面试问答(转载)

    原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/ 多线程和并发问题是Ja ...

  6. mysql utf8改utf8mb4

    由于需要用到utf8mb4,之前是utf8现在给改成utf8mb4 查看当前环境 SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' ...

  7. linux命令--head

    head 与 tail 就像它的名字一样的浅显易懂,它是用来显示开头或结尾某个数量的文字区块,head 用来显示档案的开头至标准输出中,而 tail 想当然尔就是看档案的结尾. 具体使用参考链接: h ...

  8. vsftpd 虚拟用户配置

    vsftpd 虚拟用户的作用是 通过不同的虚拟用户可以有不同的根目录. 从 2.3.5 版本之后,vsftpd增强了安全检查,如果用户被限定在了其主目录下,则该用户的主目录不能在具有写权限了,如果检查 ...

  9. django “如何”系列2:如何编写django-admin 命令

    应用可以使用manage.py注册自己的动作,例如,你可能想要为你即将发布的应用添加一个manage.py 操作.这节我们将为polls应用添加一个closepoll的命令 添加一个managemen ...

  10. Dubbo 用户手册学习笔记 —— Dubbo架构

    Dubbo的架构 节点角色说明 节点 角色说明 Provider 服务提供方 Consumer 服务消费方 Registry 服务注册与发现的注册中心 Monitor 统计服务的调用次数和调用时间的监 ...