您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: