首页 > 代码库 > 【bzoj4514】: [Sdoi2016]数字配对 图论-费用流

【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 }
View Code

 

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