[BZOJ4205][FJ2015集训] 卡牌配对 [建图+最大流]
题面
思路
二分图匹配
这道题模型显然就是个二分图匹配嘛
那我们两两判断一下然后连边匹配.....就只有30分了
因为点数是30000,建的边太多了
这张二分图,如果用dinic跑网络流的话,因为是分层图,所以优势很大,但是也不可能支撑9亿条边
所以我们要优化边的数量
优化建边
观察题目条件,发现每个数字都不大于200,而200以下的只有46个质数,且235*7=210>200
也就是说,每个数最多有3个不同的质因数,且只能从46个里面选
再看题目要求的匹配关系,发现其实等价于至少两个属性之间有共同的质因数
那么我们可以把匹配关系转化为共同质因数关系
如何转化呢?
先考虑把AB两个属性转化一下
我们需要的是让在AB两个属性上都有相同质因数的点,能够通过边连接起来
那么我们建立46*46个点,第$(i,j)$个点代表A属性有第$i$个质因数,B属性有第$j$个质因数
这样,我们把每个X卡牌连到它对应的点,从每个Y卡牌对应的点连向这个Y卡牌,即可完成转化
例如,一张X卡牌的AB属性为$(30,35)$,2,3,5,7的编号分别为1,2,3,4
因为$30=235,35=5*7$
那么它就应该连向这些点:
$(1,3),(1,4),(2,3),(2,4),(3,3),(3,4)$
这样,我们就把AB上能够有共同质因数的点,通过中间这46*46个“跳板”连接了起来
因为最多有3个不同的质因数,所以这时的边数最大是2334646,在合理范围内
同样地,我们对于BC、AC也这么做一下
最后,我们从超级源点S连到每一个X卡片,流量为1
Y卡片连向超级汇点T,流量为1
此时S-T最大流就是最大匹配对数
总边数不会大于$n1+n2+32334646$,点数则不会大于$n1+n2+346*46$,都在合理范围内,用当前弧优化的dinic可以轻松过掉
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define id(i,j) (i-1)*46+j
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') flag=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
int n,m,cnt=-1,first[200010],dep[200010],cur[200010];
int pri[210],cntp,vis[210],fac[210][10];//我就是不喜欢vector!
struct edge{
int to,next,w;
}a[2000010];
inline void add(int u,int v,int w){
a[++cnt]=(edge){v,first[u],w};first[u]=cnt;
a[++cnt]=(edge){u,first[v],0};first[v]=cnt;
}
void init(){//初始化质因数表
int i,j,k,tmp;
for(i=2;i<=200;i++){
if(!vis[i]) pri[++cntp]=i;
for(j=1;j<=cntp;j++){
k=i*pri[j];
if(k>200) break;
vis[k]=1;
if(i%pri[j]==0) break;
}
}
for(k=2;k<=200;k++){
tmp=k;i=1;
while(tmp>1){
j=pri[i];
if(tmp%j==0){
fac[k][++fac[k][0]]=i;
while(tmp%j==0) tmp/=j;
}
i++;
}
}
}
int q[200010];
bool bfs(int s,int t){
int i,u,v,head=0,tail=1;
for(i=s;i<=t;i++) dep[i]=-1,cur[i]=first[i];
q[0]=s;dep[s]=0;
while(head<tail){
u=q[head++];
for(i=first[u];~i;i=a[i].next){
v=a[i].to;
if(~dep[v]||!a[i].w) continue;
dep[v]=dep[u]+1;q[tail++]=v;
}
}
return ~dep[t];
}
int dfs(int u,int t,int limit){
if(u==t||!limit) return limit;
int i,v,f,flow=0;
for(i=cur[u];~i;i=a[i].next){
v=a[i].to;cur[u]=i;
if((dep[v]==dep[u]+1)&&(f=dfs(v,t,min(a[i].w,limit)))){
flow+=f;limit-=f;
a[i].w-=f;a[i^1].w+=f;
if(!limit) return flow;
}
}
return flow;
}
#define inf 1e9
int dinic(int s,int t){
int re=0;
while(bfs(s,t)) re+=dfs(s,t,inf);
return re;
}
int S=0,T;
int main(){
memset(first,-1,sizeof(first));
init();
n=read();m=read();int i,j,k,t1,t2,t3;
T=n+m+46*46*3+1;
for(i=1;i<=n;i++){
t1=read();t2=read();t3=read();
add(S,i,1);
for(j=1;j<=fac[t1][0];j++)
for(k=1;k<=fac[t2][0];k++)
add(i,n+id(fac[t1][j],fac[t2][k]),1);
for(j=1;j<=fac[t1][0];j++)
for(k=1;k<=fac[t3][0];k++)
add(i,n+id(fac[t1][j],fac[t3][k])+46*46,1);
for(j=1;j<=fac[t2][0];j++)
for(k=1;k<=fac[t3][0];k++)
add(i,n+id(fac[t2][j],fac[t3][k])+46*46*2,1);
}
for(i=1;i<=m;i++){
t1=read();t2=read();t3=read();
add(i+46*46*3+n,T,1);
for(j=1;j<=fac[t1][0];j++)
for(k=1;k<=fac[t2][0];k++)
add(n+id(fac[t1][j],fac[t2][k]),i+46*46*3+n,1);
for(j=1;j<=fac[t1][0];j++)
for(k=1;k<=fac[t3][0];k++)
add(n+id(fac[t1][j],fac[t3][k])+46*46,i+46*46*3+n,1);
for(j=1;j<=fac[t2][0];j++)
for(k=1;k<=fac[t3][0];k++)
add(n+id(fac[t2][j],fac[t3][k])+46*46*2,i+46*46*3+n,1);
}
printf("%d\n",dinic(S,T));
}
[BZOJ4205][FJ2015集训] 卡牌配对 [建图+最大流]的更多相关文章
- [BZOJ4205][FJ2015集训]卡牌配对
题目:卡牌配对 传送门:None 题目大意:有$n_1$张$X$类牌和$n_2$张$Y$类类牌,每张卡牌上有三个属性值:$A,B,C$.两张卡牌能够配对,当且仅当,存在至多一项属性值使得两张卡牌该项属 ...
- 【BZOJ4205】卡牌配对
Description 现在有一种卡牌游戏,每张卡牌上有三个属性值:A,B,C.把卡牌分为X,Y两类,分别有n1,n2张. 两张卡牌能够配对,当且仅当,存在至多一项属性值使得两张卡牌该项属性值互质,且 ...
- 【BZOJ4205】卡牌配对 最大流
[BZOJ4205]卡牌配对 Description 现在有一种卡牌游戏,每张卡牌上有三个属性值:A,B,C.把卡牌分为X,Y两类,分别有n1,n2张. 两张卡牌能够配对,当且仅当,存在至多一项属性值 ...
- BZOJ 4205: 卡牌配对
4205: 卡牌配对 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 173 Solved: 76[Submit][Status][Discuss] ...
- BZOJ4205卡牌配对——最大流+建图优化
题目描述 现在有一种卡牌游戏,每张卡牌上有三个属性值:A,B,C.把卡牌分为X,Y两类,分别有n1,n2张. 两张卡牌能够配对,当且仅当,存在至多一项属性值使得两张卡牌该项属性值互质,且两张卡牌类别不 ...
- 刷题总结——卡牌配对(bzoj4205网络流)
题目: Description 现在有一种卡牌游戏,每张卡牌上有三个属性值:A,B,C.把卡牌分为X,Y两类,分别有n1,n2张. 两张卡牌能够配对,当且仅当,存在至多一项属性值使得两张卡牌该项属性值 ...
- BZOJ4205 : 卡牌配对
对于两张卡牌,如果存在两种属性值不互质,则可以匹配. 只考虑200以内的质数,一共有46个,可以新建3*46*46个点来表示一类属性值中有这两种质数的卡牌. 然后对于每张卡牌,枚举它的质因子,最多只有 ...
- BZOJ-1305 dance跳舞 建图+最大流+二分判定
跟随YveH的脚步又做了道网络流...%%% 1305: [CQOI2009]dance跳舞 Time Limit: 5 Sec Memory Limit: 162 MB Submit: 2119 S ...
- 【BZOJ-1570】BlueMary的旅行 分层建图 + 最大流
1570: [JSOI2008]Blue Mary的旅行 Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 388 Solved: 212[Submit ...
随机推荐
- UISearchController(使用)
效果图1 效果图2 其实一般是在第一种情况使用的UISearchController,但是第二种情况这种又懒得去用uisearchbar+uitableview等等去处理, 其实主要是对数据源的合理使 ...
- 描述linux目录结构以及目录结构命名规定
FHS全称(Filesystem Hierarchy Standard),中文意思是目录层次标准,是linux的目录规范标准. 详情点击查看 FHS定义了两层规范: 第一层:“/”目录下的各个目录应该 ...
- 虚拟机VMware安装Kali Linux
本文讲解如何在虚拟机上安装Kali Linux,希望对大家有所帮助. 准备:一台电脑,VMware(VMware安装教程) 一.下载系统镜像文件 1.首先下载系统镜像,进入kali官网,在Downlo ...
- 单源次短路径:poj:3255-Roadblocks
Roadblocks Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 17521 Accepted: 6167 Descripti ...
- CentOS下使用Mysql
安装过程百度,然后cd /etc->vi my.cnf修改配置文件,在mysqld下添加lower_case_table_name=1和character_set_server=utf8,保存退 ...
- 十三、MySQL之IDE工具介绍及数据备份
一.IDE工具介绍 生产环境还是推荐使用mysql命令行,但为了方便我们测试,可以使用IDE工具 下载链接:https://pan.baidu.com/s/1bpo5mqj 二.MySQL数据备份 # ...
- MyBatis---集合查询(一对多)
这里的集合查询即一对多的数据联合查询.如一个用户多次登录的信息查询 要实现这样的联合查询需要在用户实体类中添加登录实体类的一个集合属性字段,表中不存在该字段. <resultMap id=&qu ...
- 4-linux基本命令
1. cd命令 cd 回当前用户 家目录 cd /home 进入home目录 (绝对路径) (相对路径) cd – 上一目录和当前目录来回切换(主要用于返回上一目录) cd . ...
- SpringBoot推荐基础包
技术交流群:233513714 Spring Boot 推荐的基础包 名称 说明 spring-boot-starter 核心 POM,包含自动配置支持.日志库和对 YAML 配置文件的支持. spr ...
- echart搭配时间轴进行展示 (本例展示的是多时间 多地区 多指标条件 )
1:照常先来几张图 看效果 2:首先 看官方文档 我把echart官方的例子给扒下来并整理了得出如下效果 上 案例图和代码 效果图 : 代码: <style type="text/c ...