BZOJ-4205 卡牌配对 最大流+线性筛+神建模
2016-03-23 17:03
204 查看
上午蛋蛋叫我去帮他调最大流,去了... 蛋蛋说,我莫名的没法运行了... 手动枚举错误,无果,扫描程序,无果... 怒了,我交上去看看情况,再帮你调....A了....问:蛋蛋你咋搞的?蛋蛋:我不会,所以照着黄学长的打的.... .......于是怒去拍蛋蛋,这道题拍的心累.....
4205: 卡牌配对
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 102 Solved: 46
[Submit][Status][Discuss]
Description
现在有一种卡牌游戏,每张卡牌上有三个属性值:A,B,C。把卡牌分为X,Y两类,分别有n1,n2张。
两张卡牌能够配对,当且仅当,存在至多一项属性值使得两张卡牌该项属性值互质,且两张卡牌类别不同。
比如一张X类卡牌属性值分别是225,233,101,一张Y类卡牌属性值分别为115,466,99。那么这两张牌是可以配对的,因为只有101和99一组属性互质。
游戏的目的是最大化匹配上的卡牌组数,当然每张卡牌只能用一次。
Input
数据第一行两个数n1,n2,空格分割。
接下来n1行,每行3个数,依次表示每张X类卡牌的3项属性值。
接下来n2行,每行3个数,依次表示每张Y类卡牌的3项属性值。
Output
输出一个整数:最多能够匹配的数目。
Sample Input
2 2
2 2 2
2 5 5
2 2 5
5 5 5
Sample Output
2
【提示】
样例中第一张X类卡牌和第一张Y类卡牌能配对,第二张X类卡牌和两张Y类卡牌都能配对。所以最佳方案是第一张X和第一张Y配对,第二张X和第二张Y配对。
另外,请大胆使用渐进复杂度较高的算法!
HINT
对于100%的数据,n1,n2≤ 30000,属性值为不超过200的正整数
Source
这个题是真的厉害,想了好久都建不出图
题解:
首先对于暴力构图,非常的好想好实现,大约能过一半,显然不行
于是要寻找可以修改的共同点,对于互质,很容易想到,只需要满足为质数一定互质,于是从质数这个角度入手,筛出200内的质数(46个)
在最暴力的模型中加入一种点,满足要求的左右点分别与它相连,边权为正无穷。
考虑到x和y只需是质数,这样的点共有至多3*46*46个(1~200质数共46个),而200<2*3*5*7,所以两侧每个点至多连出3*3*3条边。
这样建出的图看似很大,并不能跑出来,但是仍旧是分层图,对于分层图,Dinic有着十分玄学的效率O(跑得过),当然题目中也作出提示,加上当前弧优化直接硬跑!
跑得没有蛋蛋快,不开心…谁让蛋蛋是黄学长的程序翻版呢…..
code:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define maxn 30010+30010+3*46*46+1 #define maxm 4000010 #define nn 30010 int n1,n2,S,T; struct data{int to,next,cap;}edge[maxm]; int head[maxn]={0},cnt=1; struct dat{int a,b,c;}x[nn],y[nn]; void add(int u,int v,int w) { cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w; } void insert(int u,int v,int w) { add(u,v,w); add(v,u,0); } //add edge int q[maxn],h,t; int dis[maxn],cur[maxn]; bool bfs() { memset(dis,-1,sizeof(dis)); q[0]=S; dis[S]=1; h=0;t=1; while (h<t) { int j=q[h++]; for (int i=head[j]; i; i=edge[i].next) if (edge[i].cap && dis[edge[i].to]<0) dis[edge[i].to]=dis[j]+1,q[t++]=edge[i].to; } return dis[T]!=-1; } int dfs(int loc,int low) { if (loc==T) return low; int w,used=0; for (int i=head[loc]; i; i=edge[i].next) if (dis[edge[i].to]==dis[loc]+1) { w=dfs(edge[i].to,min(low-used,edge[i].cap)); used+=w; edge[i].cap-=w; edge[i^1].cap+=w; if (edge[i].cap) cur[loc]=i; if (used==low) return low; } if (!used) dis[loc]=-1; return used; } #define inf 0x7fffffff int dinic() { int tmp=0; while (bfs()) { for (int i=S; i<=T; i++) cur[i]=head[i]; tmp+=dfs(S,inf); } return tmp; } //Maxflow vector<int>v[210]; int prime[210];bool flag[210]; void get_prime(int n) { flag[1]=1; for (int i=2; i<=n; i++) { if (!flag[i]) prime[++prime[0]]=i; for (int j=1; j<=prime[0] && i*prime[j]<=n; j++) { flag[i*prime[j]]=1; if (!(i%prime[j])) break; } } for (int i=2; i<=n; i++) for (int j=1; j<=prime[0]; j++) if (!(i%prime[j])) v[i].push_back(j); } //get_prime int id[50][50],idd=0; void build(int t,int f) { int a,b,c; if (!f) a=x[t].a,b=x[t].b,c=x[t].c; else a=y[t].a,b=y[t].b,c=y[t].c; for(int i=0; i<v[a].size(); i++) for(int j=0; j<v[b].size(); j++) if(!f) insert(t,n1+n2+id[v[a][i]][v[b][j]],1); else insert(n1+n2+id[v[a][i]][v[b][j]],n1+t,1); for(int i=0;i<v[a].size(); i++) for(int j=0;j<v[c].size(); j++) if(!f) insert(t,n1+n2+id[v[a][i]][v[c][j]]+46*46,1); else insert(n1+n2+id[v[a][i]][v[c][j]]+46*46,n1+t,1); for(int i=0; i<v[b].size(); i++) for(int j=0; j<v[c].size(); j++) if(!f) insert(t,n1+n2+id[v[b][i]][v[c][j]]+46*46*2,1); else insert(n1+n2+id[v[b][i]][v[c][j]]+46*46*2,n1+t,1); } void make() { for(int i=1;i<=46;i++) for(int j=1;j<=46;j++) id[i][j]=++idd; S=0; T=n1+n2+3*46*46+1; for (int i=1; i<=n1; i++) insert(0,i,1),build(i,0); for (int i=1; i<=n2; i++) insert(n1+i,T,1),build(i,1); } //build int main() { n1=read(),n2=read(); for (int i=1; i<=n1; i++) x[i].a=read(),x[i].b=read(),x[i].c=read(); for (int i=1; i<=n2; i++) y[i].a=read(),y[i].b=read(),y[i].c=read(); get_prime(200);make(); printf("%d\n",dinic()); return 0; }
相关文章推荐
- Spring 实现数据库读写分离
- 使用 pandas 玩转股票数据
- JdbcTemplate注解注入
- block为什么用copy以及如何解决循环引用
- 来来来,做道题,一起防老年痴呆
- ElasticSearch 2 (28) - 信息聚合系列之高层概念
- Java学习笔记(一)
- hession的使用
- Java enum的用法详解
- 与WebGL有关的教程与实例
- radio接收并显示后台传值
- 关于java Socket Connection timed out: connect
- P2P之UDP穿透NAT的原理与实现 - 增强篇(附修改过的源代码)
- 谈谈开发人员自测——黑盒测试
- 打印程序入门
- 迭代子模式
- 关于APK签名
- Cg入门20:Fragment shader - 片段级模型动态变色(实现汽车动态换漆)
- 【jQuery源码】jQuery对象初始化
- Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等)