• 【bzoj3158】千钧一发 最小割


    Input

    第一行一个正整数N。

    第二行共包括N个正整数,第 个正整数表示Ai。

    第三行共包括N个正整数,第 个正整数表示Bi。

    Output

    共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值。

    Sample Input

    4
    3 4 5 12
    9 8 30 9

    Sample Output

    39

    HINT

    1<=N<=1000,1<=Ai,Bi<=10^6

    题解

    可以证明,任意两个偶数满足2

    两个奇数满足1

    (2a+1)^2+(2b+1)^2=2(2a^2+2b^2+2a+2b+1)

    一定不是完全平方数

    所以可以用最小割解决此题

    连向S表示选择偶数,连向T表示选择奇数,

    因为两个奇数,两个偶数都有一些奇怪的性质,如上,

    然后如果两个都不满足,那么就连一条边,表示只能选其中一个。

      1 #include<cstring>
      2 #include<cmath>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<cstdio>
      6 #include<queue>
      7 
      8 #define ll long long
      9 #define inf 2000000007
     10 #define N 1007
     11 #define M 1500007
     12 using namespace std;
     13 inline int read()
     14 {
     15     int x=0,f=1;char ch=getchar();
     16     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     17     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
     18     return x*f;
     19 }
     20 
     21 int ans,n,S,T;
     22 int a[N],b[N];
     23 int cnt,hed[N],nxt[M],rea[M],val[M],cur[N];
     24 int dis[N];
     25 
     26 void add(int u,int v,int w)
     27 {
     28     nxt[++cnt]=hed[u];
     29     hed[u]=cnt;
     30     rea[cnt]=v;
     31     val[cnt]=w;
     32 }
     33 void add_two_way(int u,int v,int w){add(u,v,w),add(v,u,0);}
     34 ll sqr(ll x){return x*x;}
     35 int gcd(int a,int b){return b?gcd(b,a%b):a;}
     36 bool check(int x,int y)
     37 {
     38 //    cout<<x<<" "<<y<<endl;
     39     ll sum=sqr(a[x])+sqr(a[y]),sum1=(ll)sqrt(sum);
     40     if (sqr(sum1)!=sum) return true;
     41     if (gcd(a[x],a[y])>1) return true;
     42 //    cout<<x<<" "<<y<<endl;
     43     return false;
     44 }
     45 bool bfs()
     46 {
     47     for (int i=S;i<=T;i++)dis[i]=-1;
     48     dis[S]=0;queue<int>q;q.push(S);
     49     while(!q.empty())
     50     {
     51         int u=q.front();q.pop();
     52         for (int i=hed[u];i!=-1;i=nxt[i])
     53         {
     54             int v=rea[i],w=val[i];
     55             if (w==0||dis[v]!=-1)continue;
     56             dis[v]=dis[u]+1;
     57             if (v==T)return 1;
     58             q.push(v);
     59         }
     60     }
     61     return 0;
     62 }
     63 int dfs(int u,int MX)
     64 {
     65     if (u==T||MX==0)return MX;
     66     int res=0;
     67     for (int i=cur[u];i!=-1;i=nxt[i])
     68     {
     69         int v=rea[i],w=val[i];
     70         if (dis[v]!=dis[u]+1)continue;
     71         int x=dfs(v,min(MX,w));
     72         cur[u]=i,res+=x,MX-=x;
     73         val[i]-=x,val[i^1]+=x;
     74         if (!MX)break;
     75     }
     76     if (!res)dis[u]=-1;
     77     return res;
     78 }
     79 void dinic()
     80 {
     81 //    cout<<"ans="<<ans<<endl;
     82     while(bfs())
     83     {
     84 //        cout<<2<<endl;
     85         for (int i=S;i<=T;i++)cur[i]=hed[i];
     86         ans-=dfs(S,inf);
     87 //        cout<<3<<endl;
     88     }
     89 }
     90 int main()
     91 {
     92     freopen("fzy.in","r",stdin);
     93     freopen("fzy.out","w",stdout);
     94     
     95     cnt=1;memset(hed,-1,sizeof(hed));
     96     n=read();
     97     for (int i=1;i<=n;i++)a[i]=read();
     98     for (int i=1;i<=n;i++)b[i]=read(),ans+=b[i];
     99     S=0,T=n+1;
    100     for (int i=1;i<=n;i++)
    101         if (a[i]%2==0) add_two_way(S,i,b[i]);
    102         else add_two_way(i,T,b[i]);
    103     for (int i=1;i<=n;i++)
    104         for (int j=1;j<=n;j++)
    105             if ((a[i]%2==0)&&(a[j]%2==1))
    106                 if (!check(i,j)) add_two_way(i,j,inf);
    107     dinic();
    108     printf("%d",ans);
    109 }
  • 相关阅读:
    数学系列:数学在计算机图形学中的应用
    数学系列:数学体系概览
    Math: Fibonacci
    算法系列:电磁频谱划分
    计算机系列:CUDA 深入研究
    算法系列:寻找最大的 K 个数
    算法系列:000
    算法系列:三元组和
    算法系列:单链表逆序
    堆栈区别
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8286928.html
Copyright © 2020-2023  润新知