【bzoj4514】: [Sdoi2016]数字配对 图论-费用流

【bzoj4514】: [Sdoi2016]数字配对

好像正常的做法是建二分图?

我的是拆点然后

S->i cap=b[i] cost=0

i‘->T cap=b[i] cost=0

然后能匹配的两点i,j 连 i->j‘ cap=inf cost=c[i]*c[j]

跑最大费用流,直到 cost<0 或 全部增广完

最后flow/2就是答案

  1 /* http://www.cnblogs.com/karl07/ */
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cmath>
  6 #include <algorithm>
  7 #include <queue>
  8 using namespace std;
  9
 10 #define ll long long
 11 const ll inf=1e18;
 12 const int N=1e5+5;
 13 struct edge{
 14     int from,next,to;
 15     ll v,c;
 16 }e[N];
 17 int first[N],pr[N],prime[N],inq[N],lst[N];
 18 ll A[N],B[N],C[N],dis[N],minf[N];
 19 int S=1,T=2,ade=1,P,n;
 20 queue <int> Q;
 21
 22 void addedge(int x,int y,ll v,ll c){
 23     e[++ade].to=y;
 24     e[ade].from=x;
 25     e[ade].next=first[x];
 26     e[ade].v=v;
 27     e[ade].c=c;
 28     first[x]=ade;
 29 }
 30
 31 void ADE(int x,int y,ll v,ll c){
 32     addedge(x,y,v,c);
 33     addedge(y,x,-v,0);
 34 }
 35
 36 void Prime(){
 37     for (int i=2;i<40000;i++) prime[i]=1;
 38     for (int i=2;i<40000;i++){
 39         if (prime[i]){
 40             pr[++pr[0]]=i;
 41             for (int j=i+i;j<40000;j+=i) prime[j]=0;
 42         }
 43     }
 44 }
 45
 46 bool check(ll x){
 47     if (x==1) return 0;
 48     for (int i=1;i<=pr[0] && pr[i]<x ;i++) if (!(x%pr[i])) return 0;
 49     return 1;
 50 }
 51
 52 #define s e[x].to
 53 #define v e[x].v
 54 #define cap e[x].c
 55 #define Cap e[x^1].c
 56 bool SPFA(ll &mf,ll &mc){
 57     for (int i=1;i<=n*2+2;i++) dis[i]=-inf,minf[i]=inf;
 58     Q.push(S),inq[S]=1,dis[S]=0;
 59     while (!Q.empty()){
 60         int p=Q.front();
 61         Q.pop(),inq[p]=0;
 62         for (int x=first[p];x;x=e[x].next){
 63             if (dis[s]<dis[p]+v && cap>0){
 64                 dis[s]=dis[p]+v;
 65                 lst[s]=x;
 66                 minf[s]=min(minf[p],cap);
 67                 if (!inq[s]) Q.push(s),inq[s]=1;
 68             }
 69         }
 70     }
 71     if (dis[T]==-inf) return 0;
 72     for (int x=lst[T];x;x=lst[e[x].from]) {cap-=minf[T],Cap+=minf[T];}
 73     mf+=minf[T];
 74     mc+=dis[T]*minf[T];
 75     if (mc<0){
 76         mf-=mc/dis[T]+(mc%dis[T]!=0);
 77         return 0;
 78     }
 79     return 1;
 80 }
 81
 82 void mcmf(){
 83     ll mf=0,mc=0;
 84     while (SPFA(mf,mc));
 85     printf("%lld\n",mf/2);
 86 }
 87 #undef s
 88 #undef v
 89 #undef c
 90 #undef C
 91
 92
 93 int main(){
 94     Prime();
 95     scanf("%d",&n);
 96     for (int i=1;i<=n;i++) scanf("%lld",&A[i]);
 97     for (int i=1;i<=n;i++) scanf("%lld",&B[i]);
 98     for (int i=1;i<=n;i++) scanf("%lld",&C[i]);
 99     for (int i=1;i<=n;i++){
100         ADE(S,i+2,0,B[i]);
101         ADE(i+n+2,T,0,B[i]);
102         for (int j=1;j<=n;j++){
103             if (A[i]>A[j] && A[i]%A[j]==0){
104                 if (check(A[i]/A[j])){
105                     ADE(i+2,j+n+2,C[i]*C[j],inf);
106                     ADE(j+2,i+n+2,C[i]*C[j],inf);
107                 }
108             }
109         }
110     }
111     mcmf();
112     return 0;
113 }

时间: 2024-10-06 17:02:19

【bzoj4514】: [Sdoi2016]数字配对 图论-费用流的相关文章

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

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2204  Solved: 865[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对.

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. 输出格式

【BZOJ-4514】数字配对 最大费用最大流 + 质因数分解 + 二分图 + 贪心 + 线性筛

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 726  Solved: 309[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在

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.--

[bzoj4514] [Sdoi2016]数字配对

费用流.. 先把a数组里的数全部质因数分解,判断ai/aj是否为质数,就看质因数互相抵消后是不是只剩一个质因数. 满足条件的数就连边 接下来我想拆点建二分图..然而由题解可得,连边的两个数 的质因数个数 的奇偶性肯定不同.. 就相当于自带黑白染色...所以奇数个连汇,偶数个连源就行了= = 因为有价值总和不小于0的限制.所以找到一条价值为负的增广路后,不一定能流满. 但是因为求费用流的原始对偶算法自带限制流量的功能..所以其实改一个数就能照常多路增广了= = 1 #include<cstdio>

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

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2197  Solved: 859[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在获得的价值总和不小于 0 的前提下,求最

【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.

图论(费用流):BZOJ 4514 [Sdoi2016]数字配对

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 820  Solved: 345[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在

Luogu P4068 [SDOI2016]数字配对(费用流)

Luogu P4068 [SDOI2016]数字配对(费用流) 根据质因子个数奇偶性划分肯定会形成一张二分图. 把所有的\(a\)分解质因数,记录其质因子个数. \(a_i \% a_j == 0\)且\(a_i\)的质因子比\(a_j\)质因子个数多1的时候,我们连边. 解决这个题目的关键是求出费用\(>0\)的时候的最大的流量. 我们要跑最大费用最大流,(具体实现是把边权取反) 这样在每一次的增广过程中,我们都可以保证费用最大且满足流最多. 但是写法有异议,待填坑. 原文地址:https:/