[UOJ171][WC2016]挑战NPC
sol
你可以列一个表格。
一个框子里放球的数量 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
对“半空框子”数量的贡献 | 1 | 1 | 0 | 0 |
把一个框子拆三个点。两两之间连边。
会发现,如果这三个点里一个都没有被球匹配掉,那么这三个点的最大匹配数是\(1\);如果任意一个点被一个球匹配掉了,那么剩下两个点一定可以匹配,所以最大匹配数还是\(1\);有两个点或者是三个点被匹配后最大匹配就是\(0\)。
所以,按如上方式建图,每个球向它可以放进的框子对应的的三个点都连边。跑出最大匹配后输出\(ans-n\)就好了。(因为\(n\)个球是一定可以被匹配的)
update:yyb跟我说他在WA了若干次后发现了一件有趣的事情。
因为只有增广成功时才会修改匹配,所以如果先匹配框子再匹配球的话,不能保证球一定出现在最大匹配中,所以在输出方案的时候会出问题。
所以就一定要先匹配球再匹配框子。
code
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 1005;
int T,n,m,q,to[N*N],nxt[N*N],head[N],cnt;
int match[N],vis[N],pre[N],fa[N],tim[N],idx,ans;
queue<int>Q;
void link(int u,int v)
{
to[++cnt]=v;nxt[cnt]=head[u];
head[u]=cnt;
to[++cnt]=u;nxt[cnt]=head[v];
head[v]=cnt;
}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int lca(int x,int y)
{
for (++idx;;swap(x,y))
if (x)
{
x=find(x);
if (tim[x]==idx) return x;
else tim[x]=idx,x=pre[match[x]];
}
}
void blossom(int x,int y,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];
}
}
int Aug(int S)
{
for (int i=n+3*m;i;--i)
vis[i]=pre[i]=0,fa[i]=i;
while (!Q.empty()) Q.pop();
Q.push(S);vis[S]=1;
while (!Q.empty())
{
int u=Q.front();Q.pop();
for (int e=head[u];e;e=nxt[e])
{
int v=to[e];
if (find(u)==find(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 1;
}
vis[match[v]]=1;Q.push(match[v]);
}
else
{
int gg=lca(u,v);
blossom(u,v,gg);blossom(v,u,gg);
}
}
}
return 0;
}
int main()
{
T=gi();
while (T--)
{
n=gi();m=gi();q=gi();cnt=idx=ans=0;
for (int i=n+3*m;i;--i) head[i]=match[i]=tim[i]=0;
for (int i=1;i<=q;++i)
{
int u=gi(),v=gi();
link(u+3*m,v),link(u+3*m,v+m),link(u+3*m,v+2*m);
}
for (int i=1;i<=m;++i)
link(i,i+m),link(i,i+2*m),link(i+m,i+2*m);
for (int i=n+3*m;i;--i) if (!match[i]) ans+=Aug(i);
printf("%d\n",ans-n);
for (int i=1+3*m;i<=n+3*m;++i) printf("%d ",(match[i]-1)%m+1);
puts("");
}
return 0;
}
[UOJ171][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 这道题大概就是考场上想不出来,想出来也调不出来的题. 把每个桶拆成三个互相有边的点,每个球向 ...
- [WC2016]挑战NPC
Sol 这做法我是想不到\(TAT\) 每个筐子拆成三个相互连边 球向三个筐子连边 然后跑一般图最大匹配 这三个筐子间最多有一个匹配 那么显然每个球一定会放在一个筐子里,一定有一个匹配 如果筐子间有匹 ...
- 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/ ...
随机推荐
- 转:Windows下USB接口驱动技术(一)
- 线程同步synchronized和ReentrantLock
一.线程同步问题的产生及解决方案 问题的产生: Java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),将会导致数据不准确,相互之间产生冲突. 如下例:假设有一个卖票 ...
- canvas 视频音乐播放器
canvas 视频音乐播放器 var play_nor_img_path = 'images/play_btn_n.png'; //播放按钮 正常时 60x60 px var play_sec_img ...
- 对matrix,dataframe的操作函数
1.每行(列)的平均值:rowMeans() ; colMeans() 输入:数值型矩阵:数值型数据框 输出:向量 2.每行(列)的总和:rowSums() ;colSums() 输入:数值型矩阵,数 ...
- blast+学习之search tools
search tools:blastn, blastp, blastx, tblastx, tblastn, psiblast, rpsblast, and rpstblastn 1.blastn: ...
- debian内核代码执行流程(一)
本文根据debian开机信息来查看内核源代码. 系统使用<debian下配置dynamic printk以及重新编译内核>中内核源码来查看执行流程. 使用dmesg命令,得到下面的开机信息 ...
- 定时任务 Linux cron job 初步使用
查看定时任务的命令为:crontab -l 编辑定时任务的命令为:crontab -e (编辑后立即生效 若注释可在行首加# 同vi) 定时任务说明 每一行为一 ...
- 分布式技术 webservice
web service 是一个平台独立的.低耦合的.自包含的.基于编程的web的应用程序,可使用开发的XML(标准通用标记语言下的一个字表)标准来描述.发布.发现.协调和配置这些应用程序,用于开发分布 ...
- 关于UML方法学图中类之间的关系:依赖,泛化,关联
类与类图 1) 类(Class)封装了数据和行为,是面向对象的重要组成部分,它是具有相同属性.操作.关系的对象集合的总称. 2) 在系统中,每个类具有一定的职责,职责指的是类所担任的任务,即类要完成什 ...
- Python中MySQL插入数据
sql = 'INSERT INTO course(class_name, credit, properties, teacher_name, college_given, classroom) ' ...