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

题面

BZOJ
洛谷
Uoj

Description

小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目:
有n个球,用整数1到n编号。还有m个筐子,用整数1到m编号。
每个筐子最多能装3个球。
每个球只能放进特定的筐子中。具体有e个条件,第i个条件用两个整数vi和ui描述,表示编号为vi的球可以放进编号为ui的筐子中。
每个球都必须放进一个筐子中。如果一个筐子内有不超过1个球,那么我们称这样的筐子为半空的。
求半空的筐子最多有多少个,以及在最优方案中,每个球分别放在哪个筐子中。
小N看到题目后瞬间没了思路,站在旁边看热闹的小I嘿嘿一笑:“水题!”
然后三言两语道出了一个多项式算法。
小N瞬间就惊呆了,三秒钟后他回过神来一拍桌子:
“不对!这个问题显然是NP完全问题,你算法肯定有错!”
小I浅笑:“所以,等我领图灵奖吧!”
小O只会出题不会做题,所以找到了你——请你对这个问题进行探究,并写一个程序解决此题。

Input

第一行包含1个正整数T,表示有T组数据。
对于每组数据,第一行包含3个正整数n,m,e,表示球的个数,筐子的个数和条件的个数。
接下来e行,每行包含2个整数vi,ui,表示编号为vi的球可以放进编号为ui的筐子。

Output

对于每组数据,先输出一行,包含一个整数,表示半空的筐子最多有多少个。

Sample Input

1

4 3 6

1 1

2 1

2 2

3 2

3 3

4 3

Sample Output

2

HINT

对于所有数据,T≤5,1≤n≤3m。保证 1≤vi≤n,1≤ui≤m,且不会出现重复的条件。

保证至少有一种合法方案,使得每个球都放进了筐子,且每个筐子内球的个数不超过 3。

M<=100

题解

考虑一下可以放的球数和对答案的贡献:
3个球:1
2个球:1
1个球:0
0个球:0
我们发现就是可以放的球数整除\(2\)的结果
所以,把一个篮子拆成三个
一个球还是一个球
如果一个球可以放进一个篮子里,证明着球可以与篮子拆分出来的任意一个点匹配
现在要求的相当于篮子自身能够匹配的最大数目
如果超过了两个空,那么就可以自身与自身匹配了,从而产生贡献一。

所以考虑如下构图:
每个篮子是三个点,点与点之间互相连边
每个球是一个点,可以向它可以放的篮子拆出来的三个点连边。

这样的话,因为保证所有球都有匹配,
所以最大匹配数=球数+有贡献的篮子自身的匹配

所以最后的答案就是最大匹配数-球数。

至于如何计算方案,一定优秀增广球,再增广篮子,否则会出现篮子自身优先匹配,然后球没有匹配的情况,到时方案错误(虽然答案也是对的。。。)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 1111
inline int read()
{RG int x=0,t=1;RG char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();if(ch=='-')t=-1,ch=getchar();while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return x*t;
}
struct Line{int v,next;}e[MAX*MAX];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
queue<int> Q;
int dfn[MAX],tim;
int match[MAX],pre[MAX];
int f[MAX],vis[MAX],n,m,E;
int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
int lca(int u,int v)
{++tim;u=getf(u);v=getf(v);while(dfn[u]!=tim){dfn[u]=tim;u=getf(pre[match[u]]);if(v)swap(u,v);}return u;
}
void Blossom(int x,int y,int w)
{while(getf(x)!=w){pre[x]=y,y=match[x];if(vis[y]==2)vis[y]=1,Q.push(y);if(getf(x)==x)f[x]=w;if(getf(y)==y)f[y]=w;x=pre[y];}
}
bool Aug(int S)
{for(int i=1;i<=n+m+m+m;++i)f[i]=i,vis[i]=pre[i]=0;while(!Q.empty())Q.pop();Q.push(S);vis[S]=1;while(!Q.empty()){int u=Q.front();Q.pop();for(int i=h[u];i;i=e[i].next){int v=e[i].v;if(getf(u)==getf(v)||vis[v]==2)continue;if(!vis[v]){vis[v]=2;pre[v]=u;if(!match[v]){for(int x=v,lst;x;x=lst)lst=match[pre[x]],match[x]=pre[x],match[pre[x]]=x;return true;}vis[match[v]]=1,Q.push(match[v]);}else{int w=lca(u,v);Blossom(u,v,w);Blossom(v,u,w);}}}return false;
}
void init()
{memset(h,0,sizeof(h));cnt=1;memset(dfn,0,sizeof(dfn));tim=0;memset(match,0,sizeof(match));
}
int main()
{int T=read();while(T--){n=read();m=read();E=read();init();int ans=0;for(int i=1;i<=m;++i){Add(i,i+m);Add(i+m,i);Add(i,i+m+m);Add(i+m+m,i);Add(i+m,i+m+m);Add(i+m+m,i+m);}for(int i=1;i<=E;++i){int v=read(),u=read();Add(v+m+m+m,u);Add(u,v+m+m+m);Add(v+m+m+m,u+m);Add(u+m,v+m+m+m);Add(v+m+m+m,u+m+m);Add(u+m+m,v+m+m+m);}for(int i=m+m+m+n;i;--i)if(!match[i]&&Aug(i))++ans;printf("%d\n",ans-n);for(int i=1;i<=n;++i)printf("%d ",(match[i+m+m+m]-1)%m+1);puts("");}return 0;
}

转载于:https://www.cnblogs.com/cjyyb/p/8719429.html

【BZOJ4405】【WC2016】挑战NPC(带花树)相关推荐

  1. luogu P4258 [WC2016]挑战NPC(一般图的最大匹配,带花树,建图、拆点技巧)

    整理的算法模板合集: ACM模板 luogu P4258 [WC2016]挑战NPC 如果是一堆球一堆筐,每一个筐里只能放一个球,求最大能放多少个球, 那么就是一个二分图的最大匹配问题,非常简单,我们 ...

  2. WC2016 挑战NPC

    NPC,即Non_Player Character,作为游戏很重要的一种存在-- 哎不对,扯远了. 这题出题人卖萌,明显不是NPC问题. 我们可以发现(通过前几个点找一找规律什么的)这题可以建立一个一 ...

  3. 牛客2021年七夕节比赛 F 清楚姐姐的翅膀们【带花树】

    传送门 清 楚 姐 姐 的 后 宫 有 很 多 妹 子 , 她 们 都 是 清 楚 姐 姐 的 翅 膀 . 当时觉得是匹配,就狂交了六十多发随机 题意: N N N个妹子, M M M个蝴蝶结 每个蝴 ...

  4. P4258-[WC2016]挑战NPC【带花树】

    正题 题目链接:https://www.luogu.com.cn/problem/P4258 题目大意 给出nnn个球,mmm个篮筐,每个球都可以被放入一些特定的篮筐,每个球都要放,要求球的个数小于等 ...

  5. 图论 —— 带花树算法

    [概述] 带花树算法用于解决一般图的最大匹配问题. 对于一个图 G(V,E),他的匹配 M 是二元组 (u,v) 组成的集合,其中 u,v∈V,(u,b)∈E,且 M 中不存在重复的点,当 |M| 最 ...

  6. 模板 - 一般图最大匹配(带花树)

    整理的算法模板合集: ACM模板 目录 题目描述 给出一张 n 个点 m 条边的无向图,求该图的最大匹配. 总结一下带花树算法的流程 1.每次找一个未匹配的点出来增广 2.在增广过程中,如果相邻点是白 ...

  7. luogu P6113 【模板】一般图最大匹配(带花树)

    整理的算法模板合集: ACM模板 总结一下带花树算法的流程 1.每次找一个未匹配的点出来增广 2.在增广过程中,如果相邻点是白点,或者是同一朵花中的节点,则直接跳过这个点 3.如果相邻点是一个未被匹配 ...

  8. WC前的颓废——带花树

    QAQ现在很不想写题解博客那就来写个算法吧QAQ... 带花树 题目 来看个题... UOJ79. 某机房里有\(n\)个OIer,其中有\(n\)个男生,\(0\)个女生.现在他们要两两配对. 有\ ...

  9. 【学习小记】一般图最大匹配——带花树算法

    Text 一般图的最大匹配仍然是基于寻找增广路的 增广路的定义是这样的一条路径,它不经过重复的点,并且路径两端均没有匹配,且整条路径是非匹配边-匹配边-非匹配边这样交错的. 类比二分图最大匹配的增广路 ...

最新文章

  1. excel冻结窗口怎么设置_IE浏览器弹出窗口怎么设置
  2. python统计excel出现次数_Python读取Excel一列并计算所有对象出现次数的方法
  3. Windows 7 Bcdedit 应用
  4. [ warning] [vmusr:vmtoolsd] Failed registration of app type 2 (Signals)
  5. 机器找不到 libcudnn.so.6
  6. [二分图]luogu 1640 连续攻击游戏
  7. 2.Docker技术入门与实战 --- 核心概念与安装配置
  8. 青鸟BCNT-网络信息安全工程师
  9. 27岁学前端开发,3年前端开发工资待遇
  10. 中国余数定理解题步骤
  11. 2018软科计算机科学工程排行,2018全球计算机与工程学科排名:清华第7,中国9个学科世界第一!...
  12. ubuntu16 下安装 dnw 给开发板传输文件,出现的问题以及解决方法
  13. php doctrine 使用,php – Doctrine 2 – 多数据库配置和使用
  14. sql 闩锁 原因_关于SQL Server中的闩锁
  15. LTE系统信息(1)-MIB
  16. Java 在PDF中添加骑缝章
  17. [创业之路-50] :动态股权机制 -5- 创业公司股权分配常见的坑
  18. windows内码、外码、字符映射表
  19. 用python3+ PyQt5写一个NFC模块的串口小工具的一星期
  20. oracle命令历史,查看命令历史记录及其操作时间

热门文章

  1. cmd - 命令行窗口中文乱码
  2. 谨慎跟随初始目的不被关联问题带偏
  3. 在学习中遇到的第一难点
  4. 如何控制dedecms描述的长度?
  5. Q+ Web 改版设计小结
  6. 使用 IAsyncResult 进行 .NET 异步编程(转载)
  7. 利用OpenCV的库函数Sobel和Scharr作图像的边缘检测
  8. 利用java打印正三角形_JAVA一层for循环实现打印正三角形和到三角形
  9. type=radio增加onclick没有效果_张启东:如何有效增强KTV音响效果的立体感?
  10. linux下mysql的基本用法