zoukankan      html  css  js  c++  java
  • BZOJ4514 [Sdoi2016]数字配对

    题解

      一开始看到这道题各种费用流的即视感。

      首先这个配对应该可以想到构建二分图模型。构建出二分图后就比较容易把关系转化为边了。

      但怎么构建呢?这个还是比较巧妙的,因为只有 小的数能整除大的数 且商为质数 的2个数才能配对。

      也就是说只有在质因子个数相差1的情况下可能配对,于是很容易很把数分成2个集合。

      然后在2个集合间靠关系建边。(具体怎么建就不阐述了)

      另外在前提是跑最大费用最大流的情况下,由于整张图的流与当前费用最大的增广流之间存在单调性,

      即随流变大,每次费用最大的增广流费用变小。(这个可以感性理解一下,主要是得意识到有这个性质)

      所以我们一次次跑spfa,跑到最大费用不能再小为止。

      答案就是最后的可行流。

    代码

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <algorithm>
      4 #include <cstring>
      5 typedef long long ll;
      6 using namespace std;
      7 const ll inf=1e18;
      8 const int N=405;
      9 const int M=100000;
     10 int a[N],b[N],c[N],d[N];
     11 int n,cnt,x;
     12 struct mcmf
     13 {
     14         int l,s,t,po,cnt;
     15         int v[M],nxt[M],last[N],to[M],flow[N],pre_point[N],pre_edge[N],q[N+10];
     16         ll cost[M],f[N];
     17         bool flag[N];
     18         void clr()
     19         {
     20                 l=1;
     21                 memset(last,0,sizeof(last));
     22         }
     23         void ins(int x,int y,int z,ll c)
     24         {
     25                 nxt[++l]=last[x];
     26                 last[x]=l;
     27                 to[l]=y;
     28                 v[l]=z;
     29                 cost[l]=c;
     30         }
     31         void add(int x,int y,int z,ll c)
     32         {
     33                 ins(x,y,z,c);
     34                 ins(y,x,0,-c);
     35         }
     36         bool spfa()
     37         {
     38                 for (int i=0;i<=cnt;++i)
     39                         f[i]=-inf,
     40                         flag[i]=0,
     41                         flow[i]=0;
     42                 flow[s]=1e8;
     43                 f[s]=0;
     44                 q[1]=s;
     45                 int l,r,u,y;
     46                 l=0;r=1;
     47                 flag[s]=1;
     48                 while (l!=r)
     49                 {
     50                         l=l%N+1;
     51                         u=q[l];
     52                         for (int x=last[u];x;x=nxt[x])
     53                                 if (v[x])
     54                                 {
     55                                         y=to[x];                    
     56                                         if (f[u]+cost[x]>f[y])
     57                                         {
     58                                                 f[y]=f[u]+cost[x];
     59                                                 flow[y]=min(flow[u],v[x]);
     60                                                 pre_point[y]=u;
     61                                                 pre_edge[y]=x;                                        
     62                                                 if (flag[y])    continue;
     63                                                 flag[y]=1;
     64                                                 r=r%N+1;
     65                                                 q[r]=y;
     66                                         }
     67                                 }
     68                         flag[u]=0;
     69                 }
     70                 if (flow[t])    return 1;
     71                 else return 0;
     72         }
     73         int solve()
     74         {
     75                 ll ans=0;int tot;
     76                 while (spfa())
     77                 {
     78                         po=flow[t];                    
     79                         if (ans+f[t]*flow[t]<0)
     80                         {
     81                                 tot-=ans/f[t];
     82                                 ans+=ans/f[t]*f[t];                            
     83                                 break;
     84                         }
     85                         ans+=flow[t]*f[t];
     86                         tot+=flow[t];
     87                         for (int i=t;i!=s;i=pre_point[i])
     88                         {
     89                                 int e=pre_edge[i];
     90                                 v[e]-=po;
     91                                 v[e^1]+=po;                    
     92                         }
     93                 }
     94                 return tot;
     95         }
     96 }T;
     97 int main()
     98 {
     99         scanf("%d",&n);
    100         T.clr();
    101         T.s=0;
    102         for (int i=1;i<=n;++i)
    103         {
    104                 scanf("%d",&x);
    105                 a[i]=x;
    106                 for (int j=2;j*j<=x;++j)
    107                         while (x%j==0)
    108                                 ++d[i],
    109                                 x/=j;                                        
    110                 if (x>1)    ++d[i];
    111         }
    112         T.t=n+1;
    113         T.cnt=n+1;
    114         for (int i=1;i<=n;++i)    scanf("%d",&b[i]);
    115         for (int i=1;i<=n;++i)    scanf("%d",&c[i]);
    116         for (int i=1;i<=n;++i)
    117                 if (d[i]&1)    T.add(T.s,i,b[i],0);
    118                 else T.add(i,T.t,b[i],0);
    119         for (int i=1;i<=n;++i)
    120                 for (int j=1;j<=n;++j)
    121                         if (a[i]%a[j]==0 && d[i]==d[j]+1)
    122                         {
    123                                 if (d[i]&1)        T.add(i,j,1e8,(ll)c[i]*c[j]);
    124                                 else        T.add(j,i,1e8,(ll)c[i]*c[j]);
    125                         }
    126         cout<<T.solve()<<endl;
    127         return 0;
    128 }
    View Code
  • 相关阅读:
    C# 文件类的操作---删除
    C#实现Zip压缩解压实例
    UVALIVE 2431 Binary Stirling Numbers
    UVA 10570 meeting with aliens
    UVA 306 Cipher
    UVA 10994 Simple Addition
    UVA 696 How Many Knights
    UVA 10205 Stack 'em Up
    UVA 11125 Arrange Some Marbles
    UVA 10912 Simple Minded Hashing
  • 原文地址:https://www.cnblogs.com/Bleacher/p/8053038.html
Copyright © 2011-2022 走看看