bzoj4514 [Sdoi2016]数字配对 费用流

千万不要想复杂了,倍数和质数仅仅是判断两点之间能不能匹配的条件。。

主要问题还是一个分配问题

一开始想贪心,但好像不对,然后就由反例推出了关系图,然后就是二分匹配问题。。

由于每个点入的量+出的量==数量,由于一次匹配要流两条边,对于原图是很难限制的;

但由于对称性,所以就直接建两个方向的边即可。。


码:

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define inf 999999999999999
#define ll long long
queue<int>q;
int tot=-1,hou[500005],zhong[500005],xia[500005],s,t,qj[500005],n,i,j;
struct la
{
	ll x,y,z;
}a[500005];
bool vis[500005];
ll c[500005],d[500005],ans,daan,v[500005];
bool sushu(int o)
{
	int i;
	for(i=2;i*i<=o;i++)
	{
		if(o%i==0)return 0;
	}
return 1;	
}
void jian(int a,int b,ll C,ll d)
{
	++tot,hou[tot]=xia[a],xia[a]=tot,c[tot]=d,v[tot]=C,zhong[tot]=b;
}
void jia(int a,int b,ll C,ll d)
{
jian(a,b,C,d);
jian(b,a,0,-d);	
} 
bool spfa()
{
	int i;
//	cout<<"P";
	for(i=1;i<=t;i++)d[i]=-inf;
	qj[s]=-1;
	d[s]=0;
	q.push(s);
	while(!q.empty())
	{
		int st=q.front();
		vis[st]=0;
		q.pop();
		for(i=xia[st];i!=-1;i=hou[i])
		{
			int nd=zhong[i];
			if(v[i]&&d[nd]<d[st]+c[i])
			{qj[nd]=i;
			d[nd]=d[st]+c[i];if(vis[nd]==0)q.push(nd);
			vis[nd]=1;
		   }
		}	
	}
	if(d[t]==-inf)return 0;
	ll o=qj[t],lin=inf;
	while(o!=-1)
	{
		lin=min(lin,v[o]);
	o=qj[zhong[o^1]];
	}	
	 o=qj[t];
	 ll lin2=0;
//	 cout<<lin<<" ";
	while(o!=-1)
	{
		v[o]-=lin;
		v[o^1]+=lin;
		ans+=lin*c[o];
		lin2+=c[o];
		o=qj[zhong[o^1]];
	}	daan+=lin;
	if(ans<0)
	{
	daan-=(-ans)/(-lin2);
	if((-ans)%(-lin2)!=0)daan--;
		return 0;
	}
	return 1;
}
ll mcmf()
{
	while(spfa());
	return daan;	
}
int main()
{
	memset(xia,-1,sizeof(xia));
	scanf("%d",&n);
	s=n*2+1;t=n*2+2;
	for(i=1;i<=n;i++)
	{
		scanf("%lld",&a[i].x);		
	}
	for(i=1;i<=n;i++)
	{
		scanf("%lld",&a[i].y);		
	}	
	for(i=1;i<=n;i++)
	{
		scanf("%lld",&a[i].z);		
	}
	for(i=1;i<n;i++)
	for(j=i+1;j<=n;j++)
	{
	 int l1=i,l2=j;
     if(a[l1].x<a[l2].x)swap(l1,l2);
     int o=a[l1].x/a[l2].x;
     if((a[l1].x%a[l2].x==0)&&(sushu(o)))//可以被选 
     {
jia(l1,l2+n,inf,a[l1].z*a[l2].z);
jia(l2,l1+n,inf,a[l1].z*a[l2].z);
	 }
	}
	for(i=1;i<=n;i++)jia(s,i,a[i].y,0),jia(i+n,t,a[i].y,0);
printf("%lld",mcmf()/2);
}

猜你喜欢

转载自blog.csdn.net/haobang866/article/details/79371454