专栏首页数据结构与算法BZOJ4514: [Sdoi2016]数字配对(费用流)

BZOJ4514: [Sdoi2016]数字配对(费用流)

Description

有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。

若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,

那么这两个数字可以配对,并获得 ci×cj 的价值。

一个数字只能参与一次配对,可以不参与配对。

在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。

Input

第一行一个整数 n。

第二行 n 个整数 a1、a2、……、an。

第三行 n 个整数 b1、b2、……、bn。

第四行 n 个整数 c1、c2、……、cn。

Output

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

Sample Input

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

Sample Output

4

HINT

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

Source

鸣谢Menci上传

啊啊啊啊啊费用流连边的时候把流量和费用搞混了调了两个小时QWQ

考场上主要遇到了两个问题:

1.如何保证费用大于0的时候流量最大

2.如何保证每个点不被重复使用

对于第一个问题,我们可以贪心解决

即在增广的过程中,如果发现当前路径继续增光不满足条件,那么增广到上限后的最大流量就是答案

对于第二个问题,我们可以把每个数质因数分解后,按照指数的奇偶分为左边和右边,这样连边的话就不会有重复了

#include<bits/stdc++.h>
#define int long long 
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?EOF:*p1++)
using namespace std;
const int MAXN=1e5+10;
const int INF=1e16+10;
char buf[1<<23],*p1=buf,*p2=buf;
inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int N,S=0,T=23333;
int A[MAXN],B[MAXN],C[MAXN],cnt[MAXN];
struct node
{
    int u,v,w,f,nxt;
}edge[MAXN];
int head[MAXN],num=0;

inline void add_edge(int x,int y,int z,int f)
{
    edge[num].u=x;
    edge[num].v=y;
    edge[num].w=z;
    edge[num].f=f;
    edge[num].nxt=head[x];
    head[x]=num++;
}
void AddEdge(int x,int y,int z,int f) 
{
    add_edge(x,y,z,f);
    add_edge(y,x,-z,0);
}
inline int PrimeCut(int x)
{
    int tot=0;
    for(int i=2;i<=sqrt(x);i++)
        while(x%i==0) x/=i,tot++;
    return x>1?tot+1:tot;
}
namespace Liu
{
    int dis[MAXN],vis[MAXN],Pre[MAXN],ansflow=0,anscost=0;
    bool SPFA()
    {
        queue<int>q;
        q.push(S);
        memset(dis,0x3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
        memset(Pre,0,sizeof(Pre));
        dis[S]=0;
        while(q.size()!=0)
        {
            int p=q.front();q.pop();
            vis[p]=0;
            for(int i=head[p];i!=-1;i=edge[i].nxt)
            {
                if(edge[i].f>0&&dis[edge[i].v]>dis[p]+edge[i].w)
                {
                    dis[edge[i].v]=dis[p]+edge[i].w;
                    Pre[edge[i].v]=i;
                    if(!vis[edge[i].v])
                        q.push(edge[i].v),
                        vis[edge[i].v]=1;
                }
            }
        }
        return dis[T]<INF;
    }
    bool f()
    {
        int nowflow=INF;
        for(int i=T;i!=S;i=edge[Pre[i]].u)
            nowflow=min(nowflow,edge[Pre[i]].f);
        if(anscost+nowflow*(-dis[T]) < 0) 
        {
            ansflow+=anscost/dis[T];
            return 0;
        }
        for(int i=T;i!=S;i=edge[Pre[i]].u)
            edge[Pre[i]].f-=nowflow,
            edge[Pre[i]^1].f+=nowflow;
        anscost+=nowflow*(-dis[T]);
        ansflow+=nowflow;
    //    printf("%d\n",ansflow);
        return 1; 
    }
    void MCMF()
    {
        bool flag=0;
        while(SPFA())
        {
            if( !f() )
            {
                flag=1;
                printf("%d",ansflow);
                break;
            }
        }
        if(flag==0) printf("%d",ansflow);
    }
}
void Work()
{
    for(int i=1;i<=N;i++) cnt[i]=PrimeCut(A[i]);
    for(int i=1;i<=N;i++)
        cnt[i]&1?AddEdge(S,i,0,B[i]):
                AddEdge(i+N,T,0,B[i]);
    for(int i=1;i<=N;i++)
    {
        if(cnt[i]&1)
        {
            for(int j=1;j<=N;j++)
                if( (cnt[i]+1==cnt[j]&&A[j]%A[i]==0) || (cnt[j]+1==cnt[i]&&A[i]%A[j]==0)  )
                    AddEdge(i,j+N,-C[i]*C[j],INF);    
        }
    }
    Liu::MCMF();
}
main()
{
    #ifdef WIN32
    freopen("a.in","r",stdin);
    #else
    #endif
    memset(head,-1,sizeof(head));
    N=read();
    for(int i=1;i<=N;i++) A[i]=read();
    for(int i=1;i<=N;i++) B[i]=read();
    for(int i=1;i<=N;i++) C[i]=read();
    Work();
    return 0;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 关于梯度下降算法的的一些总结

    目录:  1. 前言  2. 正文   2.1 梯度      2.2 梯度下降算法          2.2.1 批量梯度下降算法          2.2....

    Gxjun
  • Go语言实现的排列组合问题实例(n个数中取m个)

    本文实例讲述了Go语言实现的排列组合问题。分享给大家供大家参考,具体如下: (一)组合问题 组合是一个基本的数学问题,本程序的目标是输出从n个元素中取m个的所有...

    李海彬
  • 算法入门,其实可以像读小说一样有趣

    我琢磨着目录,心想终于要把这些主题搞明白了。但那本书深奥难懂,看了几周后我就放弃了。直到遇到一位优秀的算法教授后,我才认识到这些概念是多么地简单而优雅。

    CSDN技术头条
  • 【深度】小度VS最强大脑声纹识别战成平局,吴恩达详解技术原理

    【新智元导读】 2016年1月13日晚,百度人工智能代表“小度”与最强大脑选手孙亦廷在声纹识别上展开人机大战,最终双方战平。本文带来百度首席科学家吴恩达对百度声...

    新智元
  • 如何用六点教会老婆写 Python ?

    ? 来源:代码湾 链接:http://codebay.cn/post/7965.html 什么是code? code就就是一种语言,一种计算机能读懂的语言。计...

    CDA数据分析师
  • 谷歌大规模机器学习:模型训练、特征工程和算法选择 (32PPT下载)

    【新智元导读】在 ThingsExpo 会议上,谷歌软件工程师 Natalia Ponomareva 作了有关如何在大规模机器学习中取得成功的讲座。Natali...

    新智元
  • Quora 精选:现代深度学习方法中,数据重要还是算法重要?

    【新智元导读】你可能都认为数据更重要,但这个问题实际上非常复杂,不是简单的“是”或“不是”就能一言以概之。对于这个问题的理解,能够反映出对理论和实际应用问题把握...

    新智元
  • 研究提出能够自我解释的 AI 算法,辅助理解机器决策过程

    【新智元导读】加利福尼亚大学伯克利分校和马克斯普朗克信息学研究所的研究提出了一种能够自我解释的算法,有助于让人类理解机器学习的决策过程。这种被称为“指向和对齐”...

    新智元
  • 在被算法取代前,程序员或将因为物理学家而更早消失

    【新智元导读】你可能不知道,设计最早的计算机 ENIAC 的 John Mauchly 是物理学家,发明 C 语言的 Dennis Ritchie 也是物理学家...

    新智元
  • 【重磅】AI 首次在德州扑克战胜人类职业玩家,新算法让机器拥有“直觉”(附论文)

    【新智元导读】 2017年刚开年,人机大战激战正酣:从围棋上孤独求败的 Master 到人脸识别的小度,现在,国外科学家宣布,机器已经在一对一的无限注德州扑克中...

    新智元

扫码关注云+社区

领取腾讯云代金券