【刷题】UOJ #171 【WC2016】挑战NPC
小 N 最近在研究 NP 完全问题,小 O 看小 N 研究得热火朝天,便给他出了一道这样的题目:
有 \(n\) 个球,用整数 \(1\) 到 \(n\) 编号。还有 \(m\) 个筐子,用整数 \(1\) 到 \(m\) 编号。
每个筐子最多能装 3 个球。
每个球只能放进特定的筐子中。具体有 \(e\) 个条件,第 \(i\) 个条件用两个整数 \(vi\) 和 \(ui\) 描述,表示编号为 \(vi\) 的球可以放进编号为 \(ui\) 的筐子中。
每个球都必须放进一个筐子中。如果一个筐子内有不超过 \(1\) 个球,那么我们称这样的筐子为半空的。
求半空的筐子最多有多少个,以及在最优方案中,每个球分别放在哪个筐子中。
小 N 看到题目后瞬间没了思路,站在旁边看热闹的小 I 嘿嘿一笑:“水题!”
然后三言两语道出了一个多项式算法。
小 N 瞬间就惊呆了,三秒钟后他回过神来一拍桌子:
“不对!这个问题显然是 NP 完全问题,你算法肯定有错!”
小 I 浅笑:“所以,等我领图灵奖吧!”
小 O 只会出题不会做题,所以找到了你——请你对这个问题进行探究,并写一个程序解决此题。
输入格式
第一行包含 \(1\) 个正整数 \(T\) ,表示有 \(T\) 组数据。
对于每组数据,第一行包含 \(3\) 个正整数 \(n,m,e\) ,表示球的个数,筐子的个数和条件的个数。
接下来 \(e\) 行,每行包含 \(2\) 个整数 \(vi,ui\) ,表示编号为 \(vi\) 的球可以放进编号为 \(ui\) 的筐子。
输出格式
对于每组数据,先输出一行,包含一个整数,表示半空的筐子最多有多少个。
然后再输出一行,包含 \(n\) 个整数 \(p1,p2,…,pn\) ,相邻整数之间用空格隔开,表示一种最优解。其中 \(pi\) 表示编号为 \(i\) 的球放进了编号为 \(pi\) 的筐子。如果有多种最优解,可以输出其中任何一种。
样例一
input
1
4 3 6
1 1
2 1
2 2
3 2
3 3
4 3
output
2
1 2 3 3
样例二
见样例数据下载。
限制与约定
对于所有数据,\(T≤5\) ,\(1≤n≤3m\) 。保证 \(1≤vi≤n,1≤ui≤m\) ,且不会出现重复的条件。
保证至少有一种合法方案,使得每个球都放进了筐子,且每个筐子内球的个数不超过 \(3\) 。
各测试点满足以下约定:
| 测试点编号 | $m$ | 约定 |
|---|---|---|
| $1$ | $\leq 10$ | $n \leq 20,e \leq 25$ |
| $2$ | ||
| $3$ | $\leq 100$ | $e=nm$ |
| $4$ | 存在方案使得有 $m$ 个半空的筐子 | |
| $5$ | 不存在有半空的筐子的方案 | |
| $6$ | ||
| $7$ | 无 | |
| $8$ | ||
| $9$ | ||
| $10$ |
时间限制: 1s
空间限制: 256MB
题解
思路极其巧妙
我们把一个框分成三个点,并且把其中两个点连上一条边
那么一个球与一个框相连就变成了这样:

我们对这个图跑一遍带花树
那么如果只有一个球放进一个框中,这个框对应的三个点就只会有一个被匹配;而剩下的两个点因为有边相连,所以一定会相互匹配
也就是说,半空的框分出的三个点中一定在两个点相互匹配
因为题目保证球全部可以放进框中,所以匹配数一定大于等于 \(n\) ,而多出来的就是这些框分出的点自己的匹配
我们只要得出有多少自己的匹配,就知道有多少半空的框,用匹配的结果减去 \(n\) 就是答案了
要使答案最大,那么匹配的结果越大越好,所以就是跑带花树
#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define ball(a,b) ((a-1)*3+b+n)
const int MAXN=300+10,MAXM=100+10,inf=0x3f3f3f3f;
int e,n,m,fa[MAXN<<1],beg[MAXN<<1],level[MAXN<<1],to[MAXN*MAXN*8],nex[MAXN*MAXN*8],link[MAXN<<1],pre[MAXN<<1],clk,vis[MAXN<<1];
std::queue<int> q;
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline int found(int x)
{
if(fa[x]!=x)fa[x]=found(fa[x]);
return fa[x];
}
inline void insert(int x,int y)
{
to[++e]=y;
nex[e]=beg[x];
beg[x]=e;
to[++e]=x;
nex[e]=beg[y];
beg[y]=e;
}
inline int LCA(int u,int v)
{
for(clk++;;std::swap(u,v))
if(u)
{
u=found(u);
if(level[u]==clk)return u;
level[u]=clk;u=pre[link[u]];
}
}
inline void blossom(int u,int v,int lca)
{
while(found(u)!=lca)
{
pre[u]=v,v=link[u];
if(vis[v]==2)vis[v]=1,q.push(v);
if(found(u)==u)fa[u]=lca;
if(found(v)==v)fa[v]=lca;
u=pre[v];
}
}
inline int bfs(int s)
{
for(register int i=1;i<=n+3*m;++i)fa[i]=i;
memset(pre,0,sizeof(pre));
memset(vis,0,sizeof(vis));
while(!q.empty())q.pop();
vis[s]=1;
q.push(s);
while(!q.empty())
{
int x=q.front();
q.pop();
for(register int i=beg[x];i;i=nex[i])
{
if(found(x)==found(to[i])||vis[to[i]]==2)continue;
if(!vis[to[i]])
{
vis[to[i]]=2;
pre[to[i]]=x;
if(!link[to[i]])
{
for(register int p=to[i],las;p;p=las)las=link[pre[p]],link[p]=pre[p],link[pre[p]]=p;
return 1;
}
vis[link[to[i]]]=1;q.push(link[to[i]]);
}
else
{
int lca=LCA(x,to[i]);
blossom(x,to[i],lca);blossom(to[i],x,lca);
}
}
}
return 0;
}
int main()
{
static int T,l,ans;
read(T);
while(T--)
{
e=ans=0;
memset(beg,0,sizeof(beg));
memset(link,0,sizeof(link));
read(n);read(m);read(l);
for(register int i=1;i<=l;++i)
{
int u,v;read(u);read(v);
for(register int k=1;k<=3;++k)insert(u,ball(v,k));
}
for(register int i=1;i<=m;++i)insert(ball(i,1),ball(i,3));
for(register int i=1;i<=n+3*m;++i)
if(!link[i])ans+=bfs(i);
write(ans-n,'\n');
for(register int i=1;i<=n;++i)write((link[i]-n+2)/3,' ');
puts("");
}
return 0;
}
【刷题】UOJ #171 【WC2016】挑战NPC的更多相关文章
- [WC2016]挑战NPC(一般图最大匹配)
[WC2016]挑战NPC(一般图最大匹配) Luogu 题解时间 思路十分有趣. 考虑一个筐只有不多于一个球才有1的贡献代表什么. 很明显等效于有至少两个位置没有被匹配时有1的贡献. 进而可以构造如 ...
- [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 这道题大概就是考场上想不出来,想出来也调不出来的题. 把每个桶拆成三个互相有边的点,每个球向 ...
- [UOJ171][WC2016]挑战NPC
uoj luogu bzoj sol 你可以列一个表格. 一个框子里放球的数量 0 1 2 3 对"半空框子"数量的贡献 1 1 0 0 把一个框子拆三个点.两两之间连边. 会发现 ...
- [BZOJ]4405: [wc2016]挑战NPC(带花树)
带花树模板 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; ...
- [WC2016]挑战NPC
Sol 这做法我是想不到\(TAT\) 每个筐子拆成三个相互连边 球向三个筐子连边 然后跑一般图最大匹配 这三个筐子间最多有一个匹配 那么显然每个球一定会放在一个筐子里,一定有一个匹配 如果筐子间有匹 ...
- bzoj 4405: [wc2016]挑战NPC【带花树】
把每个筐子拆成3个,分别表示放0/1/2个,然后把这三个点两两连起来,每一个可以放在筐里的球都想这三个点连边. 这样可以发现,放0个球的时候,匹配数为1,放1个球的时候,匹配数为1,放2个球的时候,匹 ...
- 刷题[极客大挑战 2019]HardSQL
解题思路 打开是一个登陆框,考点sql注入了,先正常尝试一波 发现居然是get类型 输入and发现有waf过滤,那fuzz一波看看过滤了什么 fuzz union被过滤,并且绕过union的几种方法同 ...
- 「WC2016」挑战NPC
「WC2016」挑战NPC 解题思路 这个题建图非常厉害,带花树什么的只会口胡根本写不动,所以我写了机房某大佬教我的乱搞. 考虑把一个筐 \(x\) 拆成 \(x1,x2,x3\) 三个点,且这三个点 ...
- 【BZOJ4405】【WC2016】挑战NPC(带花树)
[BZOJ4405][WC2016]挑战NPC(带花树) 题面 BZOJ 洛谷 Uoj Description 小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目: 有n个 ...
随机推荐
- HDU 4418 Time travel
Time travel http://acm.hdu.edu.cn/showproblem.php?pid=4418 分析: 因为走到最后在折返,可以将区间复制一份,就变成了只往右走,01234321 ...
- 一个只有十行的精简MVVM框架(下篇)
本文来自网易云社区. 让我们来加点互动 前面学生信息的身高的单位都是默认m,如果新增一个需求,要求学生的身高的单位可以在m和cm之间切换呢? 首先需要一个变量来保存度量单位,因此这里必须用一个新的Mo ...
- 使用httpClient获取请求cookie
package mytest; import java.util.ArrayList; import java.util.List; import org.apache.http.NameValueP ...
- synchronized 详细解说
转自 http://blog.csdn.net/javazejian/article/details/72828483 出自[zejian的博客] 写的很详细很好,做下记录 本篇主要是对Java并发 ...
- ubuntu ssh配置
Secure Shell (SSH) is a cryptographic network protocol for operating network services securely over ...
- docker容器学习笔记
docker是通过内核虚拟化技术来提供容器的资源隔离与安全保障. docker组成: docker client.docker server.docker组件(镜像(image).容器(contain ...
- vscode开发智能合约
开发工具 EOS 开发终极神器-vscode (你绝对找不到的干货) lome · 2018年04月19日 · 最后由 18636292520 回复于 2018年09月15日 · 15672 次阅读 ...
- C#调用mingw的so库时无法加载DLL###.so 找不到指定的模块
使用C#调用mingw的so,报了c# 无法加载DLL“###.so”,: 找不到指定的程序. (异常来自 HRESULT:0x8007007E)开始以为是dll路径问题,使用全路径确认正确后仍然无法 ...
- Bcp 使用心得【转】
在做这方面研究的时候,的确遇到了不少麻烦. 首先在做bcp的时候,要开通大数据量访问权限 一.基于sql语句的导入导出 如果是基于SQL语句的导入导出,需要使用存储过程“master..xp_cmds ...
- 《剑指Offer》题二十一~题三十
二十一.调整数组顺序使奇数位于偶数前面 题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分. 测试用例: 功能测试:输入数组中的奇 ...