zoukankan      html  css  js  c++  java
  • BZOJ4514[Sdoi2016]数字配对——最大费用最大流

    题目描述

    有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。
    若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,
    那么这两个数字可以配对,并获得 ci×cj 的价值。
    一个数字只能参与一次配对,可以不参与配对。
    在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。

    输入

    第一行一个整数 n。
    第二行 n 个整数 a1、a2、……、an。
    第三行 n 个整数 b1、b2、……、bn。
    第四行 n 个整数 c1、c2、……、cn。

    输出

     一行一个数,最多进行多少次配对

    样例输入

    3
    2 4 8
    2 200 7
    -1 -2 1

    样例输出

    4

    提示

     n≤200,ai≤10^9,bi≤10^5,∣ci∣≤10^5

    有数量上限、有价值,显然费用流,因为题目要求费用不小于$0$,所以用最大费用最大流。将每个点拆成两个点$i$和$i'$,分别与源点和汇点连边,流量为$b[i]$、费用为$0$。枚举任意两个数判断是否能匹配。因为$i$与$j$能匹配,$j$就能与$i$匹配,所以将$i$与$j'$连边、$j$与$i'$连边,流量为$INF$、费用为$-c[i]*c[j]$(因为跑最大费用最大流,边权取反)。每次$SPFA$找到一条增广路,如果加上之后答案满足要求就继续增广,否则就停止。因为一对数的匹配算了两次,所以最后答案除$2$即可。

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    #define INF 1000000000000000ll
    #define inf 1000000000
    using namespace std;
    int head[1000];
    int next[100000];
    int to[100000];
    ll v[100000];
    int c[100000];
    int f[1000];
    int from[100000];
    int tot=1;
    int S,T;
    ll ans;
    int n;
    int A[300];
    int B[300];
    int C[300];
    queue<int>q;
    int vis[1000];
    ll d[1000];
    int maxflow;
    void add(int x,int y,ll z,int w)
    {
    	next[++tot]=head[x];
    	head[x]=tot;
    	to[tot]=y;
    	v[tot]=z;
    	c[tot]=w;
    	from[tot]=x;
    	next[++tot]=head[y];
    	head[y]=tot;
    	to[tot]=x;
    	v[tot]=-z;
    	c[tot]=0;
    	from[tot]=y;
    }
    bool result()
    {
    	int now=T;
    	int flow=inf;
    	while(now!=S)
    	{
    		flow=min(flow,c[f[now]]);
    		now=from[f[now]];
    	}
    	if(ans+d[T]*flow<=0)
    	{
    		ans+=d[T]*flow;
    		maxflow+=flow;
    	}
    	else
    	{
    		maxflow+=fabs(ans)/fabs(d[T]);
    		return 1;
    	}
    	now=T;
    	while(now!=S)
    	{
    		c[f[now]]-=flow;
    		c[f[now]^1]+=flow;
    		now=from[f[now]];
    	}
    	return 0;
    }
    bool SPFA()
    {
        for(int i=1;i<=T;i++)
        {
            d[i]=INF;
        }
        d[S]=0;
        q.push(S);
        vis[S]=1;
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            vis[now]=0;
            for(int i=head[now];i;i=next[i])
            {
                if(!c[i])
                {
                    continue;
                }
                if(d[to[i]]>d[now]+v[i])
                {
                    d[to[i]]=d[now]+v[i];
                    f[to[i]]=i;
                    if(!vis[to[i]])
                    {
                        q.push(to[i]);
                        vis[to[i]]=1;
                    }
                }
            }
        }
        return d[T]!=INF;
    }
    void find_max()
    {
    	while(SPFA())
    	{
    		if(result())
    		{
    			break;
    		}
    	}
    }
    bool check(int x,int y)
    {
    	if(x<y)
    	{
    		swap(x,y);
    	}
    	if(x%y)
    	{
    		return false;
    	}
    	int d=x/y;
    	for(int i=2;i*i<=d;i++)
    	{
    		if(d%i==0)
    		{
    			return false;
    		}
    	}
    	return true;
    }
    int main()
    {
    	scanf("%d",&n);
    	S=2*n+1,T=S+1;
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&A[i]);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&B[i]);
    		add(S,i,0,B[i]);
    		add(i+n,T,0,B[i]);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&C[i]);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=i+1;j<=n;j++)
    		{
    			if(check(A[i],A[j]))
    			{
    				add(i,n+j,-1ll*C[i]*C[j],1<<30);
    				add(j,n+i,-1ll*C[i]*C[j],1<<30);
    			}
    		}
    	}
    	find_max();
    	printf("%d",maxflow/2);
    }
  • 相关阅读:
    小程序查看导航
    PHP计算两个坐标之间的距离
    微信小程序获取位置
    小程序重置index,重置item
    nmap使用教程
    boost checked_delete提升安全性
    转: 带你玩转Visual Studio——带你理解多字节编码与Unicode码
    visual studio 开发linux程序
    stl 比较和boost LessThanComparable
    c++11 auto unique_ptr 等
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/10569763.html
Copyright © 2011-2022 走看看