【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;
}

【BZOJ4405】【WC2016】挑战NPC(带花树)的更多相关文章

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

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

  2. [bzoj4405][wc2016]挑战NPC

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

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

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

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

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

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

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

  6. [WC2016]挑战NPC

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

  7. [UOJ171][WC2016]挑战NPC

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

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

    正题 题目链接:https://www.luogu.com.cn/problem/P4258 题目大意 给出\(n\)个球,\(m\)个篮筐,每个球都可以被放入一些特定的篮筐,每个球都要放,要求球的个 ...

  9. 「WC2016」挑战NPC

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

随机推荐

  1. 一个经典的PHP加密解密算法authcode

    项目中有时我们需要使用PHP将特定的信息进行加密,也就是通过加密算法生成一个加密字符串,这个加密后的字符串可以通过解密算法进行解密,便于程序对解密后的信息进行处理.最常见的应用在用户登录以及一些API ...

  2. Kettle定时执行

    1,Kettle跨平台使用.    例如:在AIX下(AIX是IBM商用UNIX操作系统,此处在LINUX/UNIX同样适用),运行Kettle的相关步骤如下:    1)进入到Kettle部署的路径 ...

  3. iOS 关于在提交了APP等待审核之后,发现小Bug需要再提一个版本的说明

    昨天晚上加班到深夜终于将APP推上去,今天早上过来再测试一遍的时候,发现需要一个小调整.而此时应用的状态是正在等待审核,随手记录一下这种情况下,提交一个新版本的做法,有需要的可以参考一下. 01-进入 ...

  4. loadrunner-录制脚本,设置代理,参数化,校验点,关联

    详细记录一个脚本制作过程相关知识点 制作脚本 因为要做网页所以选择web协议,根据实际需要选择 选择浏览器地址,打开的网页网址,脚本存储地址以及初始化脚本,初始化脚本的目的是执行用例后不再执行此脚本中 ...

  5. Unity中几个特殊路径在各个平台的访问方式

    1.文件路径Resources:Unity在发布成移动端项目后,其他文件路径都将不存在,但是如果有一些必要的资源,可以放在Resources文件夹下,因为这个文件夹下的所有资源是由Unity内部进行调 ...

  6. Select 、Poll 和 Epoll

    作用 Epoll 和 Select 的作用都是为了多I/O同步复用的问题,利用Epoll.Poll或Select函数指定内核监听多个I/O的读.写.异常事件,避免每一个I/O都指定一个处理线程,导致开 ...

  7. Python的sys.argv使用说明

    刚开始使用这个参数的时候,很不明白其含义.网上搜索很多都是贴的官网上面的一则实例,说看懂,就明白.可是,我看不懂.现在在回头看这个参数使用,并不是很麻烦. 举几个小例子就明白了. 创建一个脚本,内容如 ...

  8. Paper Reading - Long-term Recurrent Convolutional Networks for Visual Recognition and Description ( CVPR 2015 )

    Link of the Paper: https://arxiv.org/abs/1411.4389 Main Points: A novel Recurrent Convolutional Arch ...

  9. Hyperledger_Fabric_Model

    Hyperledger_Fabric_Model 本部分描述了Hyperledger Fabric的主要设计特点 Assets: 资产定义使得任何东西都可以通过货币值在网络中交易,从食物到老爷车再到期 ...

  10. nhibernate中执行SQL语句

    在有些时候,可能需要直接执行SQL语句.存储过程等,但nhibernate并没有提供一种让我们执行SQL语句的方法,不过可以通过一些间接的方法来实现. 下面给出一个在nhibernate中执行SQL语 ...