来自FallDream的博客,未经允许,请勿转载,谢谢。


小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目:
有n个球,用整数1到n编号。还有m个筐子,用整数1到m编号。
每个筐子最多能装3个球。
每个球只能放进特定的筐子中。具体有e个条件,第i个条件用两个整数vi和ui描述,表示编号为vi的球可以放进编号为ui的筐子中。
每个球都必须放进一个筐子中。如果一个筐子内有不超过1个球,那么我们称这样的筐子为半空的。
求半空的筐子最多有多少个,以及在最优方案中,每个球分别放在哪个筐子中。
小N看到题目后瞬间没了思路,站在旁边看热闹的小I嘿嘿一笑:“水题!”
然后三言两语道出了一个多项式算法。
小N瞬间就惊呆了,三秒钟后他回过神来一拍桌子:
“不对!这个问题显然是NP完全问题,你算法肯定有错!”
小I浅笑:“所以,等我领图灵奖吧!”
小O只会出题不会做题,所以找到了你——请你对这个问题进行探究,并写一个程序解决此题。
T<=5  n<=300 m<=100
 
考虑每个筐子拆成3个点,在被匹配走0/1/2/3个点的情况下能够产生的最大匹配和想要的贡献相同
只需要在其中两个点之间连一条边就好啦
然后带花树
其实我是想贴个模板
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define MN 600
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
int head[MN+],vis[MN+],cnt=,n,m,Q,q[MN*MN],now=,mark[MN+],match[MN+],ne[MN+],fa[MN+],top,tail;
struct edge{int to,ne;}e[MN*MN+];
inline int getfa(int x){return !fa[x]?x:fa[x]=getfa(fa[x]);}
inline void ins(int f,int t)
{
e[++cnt]=(edge){t,head[f]};head[f]=cnt;
e[++cnt]=(edge){f,head[t]};head[t]=cnt;
} int Lca(int x,int y)
{
++now;
for(;;swap(x,y))
if(x!=-)
{
x=getfa(x);
if(vis[x]==now) return x;
vis[x]=now;
if(match[x]) x=ne[match[x]];
else x=-;
}
} void Unit(int x,int y)
{
x=getfa(x);y=getfa(y);
if(x!=y) fa[x]=y;
} void group(int a,int p)
{
for(;a!=p;)
{
int b=match[a],c=ne[b];
if(getfa(c)!=p) ne[c]=b;
if(mark[b]==) mark[q[++top]=b]=;
if(mark[c]==) mark[q[++top]=c]=;
Unit(a,b);Unit(b,c);
a=c;
}
} void Solve(int x)
{
for(int i=;i<=n+*m;++i) ne[i]=fa[i]=mark[i]=vis[i]=;
mark[x]=;q[top=tail=]=x;
for(;!match[x]&&top>=tail;++tail)
{
int y=q[tail];
for(int i=head[y];i;i=e[i].ne)
{
int v=e[i].to;
if(match[y]==v||mark[v]==||getfa(y)==getfa(v)) continue;
if(mark[v]==)
{
int lca=Lca(y,v);
if(getfa(y)!=lca) ne[y]=v;
if(getfa(v)!=lca) ne[v]=y;
group(y,lca);
group(v,lca);
}
else if(!match[v])
{
ne[v]=y;
for(int u=v;u;)
{
int w=ne[u],ww=match[w];
match[w]=u,match[u]=w;
u=ww;
}
return;
}
else
{
ne[v]=y;
mark[q[++top]=match[v]]=;
mark[v]=;
}
}
}
} int main()
{
for(int T=read();T;--T)
{
memset(head,,sizeof(head));
memset(match,,sizeof(match));cnt=;
n=read();m=read();Q=read();
for(int i=;i<=Q;++i)
{
int x=read(),y=read();
ins(x,y+n);ins(x,y+n+m);ins(x,y+n+m+m);
}
for(int i=;i<=m;++i) ins(i+n,i+n+m);
for(int i=;i<=n+*m;++i)
if(!match[i]) Solve(i);
int ans=;
for(int i=;i<=n+*m;++i) if(match[i]) ++ans;
printf("%d\n",(ans>>)-n);
}
return ;
}
 
 

[bzoj4405][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. BZOJ 4405 [wc2016]挑战NPC 带花树 一般图最大匹配

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

  4. [WC2016]挑战NPC

    Sol 这做法我是想不到\(TAT\) 每个筐子拆成三个相互连边 球向三个筐子连边 然后跑一般图最大匹配 这三个筐子间最多有一个匹配 那么显然每个球一定会放在一个筐子里,一定有一个匹配 如果筐子间有匹 ...

  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. 【BZOJ4405】【WC2016】挑战NPC(带花树)

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

  8. 「WC2016」挑战NPC

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

  9. UOJ171 【WC2016】挑战NPC

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

随机推荐

  1. css精简命名

    想写写前言啥的,发现自己是前言无能星人. 简单吐吐槽好了,来到新公司,接手公司之前的项目,我想着也就是改改bug,慢慢来吧,粗略看了看这个项目的代码,目前仅看了html和css样式的,忍不住吐血三升. ...

  2. 09-TypeScript中的继承

    在后端开发语言中,继承是非常重要的概念,继承可以让子类具有父类的成员和方法,通过实例化子类,就可以访问父类的成员和方法. 在JavaScript中,需要通过原型模式来模拟继承的实现.而在TypeScr ...

  3. 原始的Ajax方法 (异步的 JavaScript 和 XML -- (Extensible Markup Language 可扩展标记语言))

    <script language="javascript" type="text/javascript"> var request = false; ...

  4. ASP.NET CORE 自定义视图组件(ViewComponent)注意事项

    *红色字体为固定命名,蓝色为一般命名规则,黄色为ASP.NET CORE 默认查找文件名 概要:1.简单ViewComponent的用法 2.ViewComponent控制器返回值  3.注意事项 1 ...

  5. c# 字符串的内存分配和驻留池( 转 )

    刚开始学习C#的时候,就听说CLR对于String类有一种特别的内存管理机制:有时候,明明声明了两个String类的对象,但是他们偏偏却指向同一个实例.如下: string s1 = "he ...

  6. 使用 vi 命令

    一.vi是什么 vi命令是UNIX操作系统和类UNIX操作系统中最通用的全屏幕纯文本编辑器. Linux中的vi编辑器叫vim,它是vi的增强版(vi Improved),与vi编辑器完全兼容,而且实 ...

  7. Couchbase忘记登录密码怎么办

    以下都为root用户操作: 1.先关闭couchbase /opt/couchbase/etc/couchbase_init.d stop 2.切换到下面的路径,删除这个目录下除logs的所有文件,按 ...

  8. 面向对象中Object常用属性总结

    学完Object属性,自己总结一些常用是Object常用属性. Object.prototype:属性表示Object的原型对象. 属性: Object.prototype.constructor:特 ...

  9. Windows10下的docker安装与入门 (二)使用docker引擎在容器中运行镜像

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何 ...

  10. Ubuntu下发射wifi

    iphone要连接的话,mode选Ad-hoc, wifi密码要用WEP 40/128-bit key模式