• dtoi2678「SDOI2016」数字配对


    题意:

         有 $ n $ 种数字,第 $ i $ 种数字是 $ a_i $、有 $ b_i $ 个,权值是 $ c_i $。

        若两个数字 $ a_i $、$ a_j $ 满足,$ a_i $ 是 $ a_j $ 的倍数,且 $ a_i / a_j $ 是一个质数,那么这两个数字可以配对,并获得 $ c_i cdot c_j $ 的价值。
        一个数字只能参与一次配对,可以不参与配对。
        在获得的价值总和不小于 $ 0 $ 的前提下,求最多进行多少次配对。

        $ n leq 200 $,$ a_i leq 10 ^ 9 $,$ b_i leq 10 ^ 5 $,$ left| c_i ight| leq 10 ^ 5 $。

    题解:

         阅读题目,观察到“配对”,“价值”,还有“只能参与一次配对”,容易联想到费用流。但是如果直接连边,似乎无法保证每个数字只能用 $b[i]$ 次。考虑这种配对问题,普通的费用流一般是怎么建边的,就是一些放左边,一些放右边,然后左右连边。但这道题似乎没有明显的划分依据。

         先考虑把各种边连上,这样就连出来一个图(当它是无向图),想要将其划分为左右两边,相当于这张图可以 $0/1$ 染色,即这张图是二分图。那这张图是不是二分图?可以发现,对于图中任意一个环,也就是从一个点出发回到自己本身,每走一步必然是质因子次数总和变化 $1$,那么必然是走了偶数步。换句话说,这张图所有的环,都是偶环,那么就是二分图了。

         然后问题就很简单了,二分图染色一下,$0$ 放左边,$1$ 放右边,连边完二分+费用流即可。

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    const long long INF=1e18;
    int n,aa[202],b[202],c[202],p[205],s=201,s2=202,t=203,ys[202];
    long long d[205],a[205];
    bool fl[205];
    struct Edge{
        int from,to;
        long long cap,flow,cost;
        Edge(int u,int v,long long c,long long f,long long w):from(u),to(v),cap(c),flow(f),cost(w){}
    };
    vector<Edge>edges;
    vector<int>g[205],y[205];
    void init(){
        for (int i=1;i<=t;i++)g[i].clear();
        edges.clear();
    }
    void add(int from,int to,long long cap,long long cost){
        edges.push_back(Edge(from,to,cap,0,cost));
        edges.push_back(Edge(to,from,0,0,-cost));
        g[from].push_back(edges.size()-2);
        g[to].push_back(edges.size()-1); 
    }
    bool spfa(int s,int t,long long& flow,long long& cost){
        for (int i=1;i<=t;i++)d[i]=-INF;
        d[s]=0;fl[s]=1;a[s]=INF;
        queue<int>q;q.push(s);memset(fl,0,sizeof(fl));
        while(!q.empty())
        {
            int u=q.front();q.pop();
            fl[u]=0;
            for (int i=0;i<g[u].size();i++)
            {
                Edge e=edges[g[u][i]];
                if (e.cap>e.flow && d[u]+e.cost>d[e.to])
                {
                    d[e.to]=d[u]+e.cost;
                    p[e.to]=g[u][i];
                    a[e.to]=min(a[u],e.cap-e.flow);
                    if (!fl[e.to]){q.push(e.to);fl[e.to]=1;}
                }
            }
        }
        if (d[t]==-INF)return false;
        flow+=a[t];cost+=d[t]*a[t];
        for (int u=t;u!=s;u=edges[p[u]].from)
        {
            edges[p[u]].flow+=a[t];edges[p[u]^1].flow-=a[t];
        }
        return true;
    }
    void dfs(int x){
        for (int i=0;i<y[x].size();i++)
        if (ys[y[x][i]]==-1)
        {
            ys[y[x][i]]=(ys[x]^1);dfs(y[x][i]);
        }
    }
    bool pd(long long x){
        init();add(s,s2,x,0);
        for (int i=1;i<=n;i++)
        if (ys[i]==0)
        {
            add(s2,i,b[i],0);
            for (int j=0;j<y[i].size();j++)add(i,y[i][j],INF,(long long)c[i]*c[y[i][j]]);
        }
        else add(i,t,b[i],0);
        long long flow=0,cost=0;
        while(spfa(s,t,flow,cost));
        return (flow==x && cost>=0);
    }
    bool isprim(int x){
        for (int i=2;i*i<=x;i++)
        if (x%i==0)return false;
        return true;
    }
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)scanf("%d",&aa[i]);
        for (int i=1;i<=n;i++)scanf("%d",&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 (aa[i]%aa[j]==0 && isprim(aa[i]/aa[j]) || aa[j]%aa[i]==0 && isprim(aa[j]/aa[i]))
        {
            y[i].push_back(j);y[j].push_back(i);
        }
        memset(ys,-1,sizeof(ys));
        for (int i=1;i<=n;i++)if (ys[i]==-1){ys[i]=0;dfs(i);}
        long long lef=0,righ=1000000000,mid;
        while(lef<righ)
        {
            mid=(lef+righ+1)/2;
            if (pd(mid))lef=mid;else righ=mid-1;
        }
        printf("%lld
    ",lef);
        return 0;
    }
  • 相关阅读:
    2019-2020-1 20175312 20175333 实验五 通讯协议设计
    2019-2020-1 20175312 20175333 实验四 外设驱动程序设计
    2019-2020-1 20175312 20175333 实验三 并发程序
    2019-2020-1 20175312 20175321 20175333 实验二 固件程序设计
    2019-2020-1 20175312 20175321 20175333 实验一 开发环境的熟悉
    2018-2019-1 20175312 《信息安全系统设计基础》第3周学习总结
    2019-2020-1 20175312 《信息安全系统设计基础》第2周学习总结
    2019-2020-1 20175312 《信息安全系统设计基础》第1周学习总结
    20175312 2018-2019-2 实验五 网络编程与安全 实验报告
    20175312 2018-2019-2 实验四 Android程序设计 实验报告
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/14406969.html
Copyright © 2020-2023  润新知